Commit 1773708f by tonihei Committed by Oliver Woodman

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
parent 23afdd6f
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
* Add support for lazy preparation of playlist media sources in * Add support for lazy preparation of playlist media sources in
`ConcatenatingMediaSource` `ConcatenatingMediaSource`
([#3972](https://github.com/google/ExoPlayer/issues/3972)). ([#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: * HLS:
* Allow injection of custom playlist trackers. * Allow injection of custom playlist trackers.
* Add method to `BandwidthMeter` to return the `TransferListener` used to gather * Add method to `BandwidthMeter` to return the `TransferListener` used to gather
......
...@@ -162,7 +162,7 @@ import java.util.Collections; ...@@ -162,7 +162,7 @@ import java.util.Collections;
enabledRenderers = new Renderer[0]; enabledRenderers = new Renderer[0];
window = new Timeline.Window(); window = new Timeline.Window();
period = new Timeline.Period(); 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 // Note: The documentation for Process.THREAD_PRIORITY_AUDIO that states "Applications can
// not normally change to this priority" is incorrect. // not normally change to this priority" is incorrect.
......
...@@ -21,6 +21,7 @@ import com.google.android.exoplayer2.Format; ...@@ -21,6 +21,7 @@ import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.source.TrackGroup; import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.source.chunk.MediaChunk; import com.google.android.exoplayer2.source.chunk.MediaChunk;
import com.google.android.exoplayer2.upstream.BandwidthMeter; 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.Clock;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import java.util.List; import java.util.List;
...@@ -137,11 +138,15 @@ public class AdaptiveTrackSelection extends BaseTrackSelection { ...@@ -137,11 +138,15 @@ public class AdaptiveTrackSelection extends BaseTrackSelection {
} }
@Override @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( return new AdaptiveTrackSelection(
group, group,
tracks, tracks,
bandwidthMeter, Assertions.checkNotNull(bandwidthMeter),
minDurationForQualityIncreaseMs, minDurationForQualityIncreaseMs,
maxDurationForQualityDecreaseMs, maxDurationForQualityDecreaseMs,
minDurationToRetainAfterDiscardMs, minDurationToRetainAfterDiscardMs,
......
...@@ -1206,7 +1206,9 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -1206,7 +1206,9 @@ public class DefaultTrackSelector extends MappingTrackSelector {
rendererTrackSelections[i] = rendererTrackSelections[i] =
Assertions.checkNotNull(adaptiveTrackSelectionFactory) Assertions.checkNotNull(adaptiveTrackSelectionFactory)
.createTrackSelection( .createTrackSelection(
rendererTrackGroups.get(override.groupIndex), override.tracks); rendererTrackGroups.get(override.groupIndex),
getBandwidthMeter(),
override.tracks);
} }
} }
} }
...@@ -1352,7 +1354,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -1352,7 +1354,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
formatSupports, formatSupports,
mixedMimeTypeAdaptationSupports, mixedMimeTypeAdaptationSupports,
params, params,
adaptiveTrackSelectionFactory); adaptiveTrackSelectionFactory,
getBandwidthMeter());
} }
if (selection == null) { if (selection == null) {
selection = selectFixedVideoTrack(groups, formatSupports, params); selection = selectFixedVideoTrack(groups, formatSupports, params);
...@@ -1365,7 +1368,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -1365,7 +1368,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
int[][] formatSupport, int[][] formatSupport,
int mixedMimeTypeAdaptationSupports, int mixedMimeTypeAdaptationSupports,
Parameters params, Parameters params,
TrackSelection.Factory adaptiveTrackSelectionFactory) TrackSelection.Factory adaptiveTrackSelectionFactory,
@Nullable BandwidthMeter bandwidthMeter)
throws ExoPlaybackException { throws ExoPlaybackException {
int requiredAdaptiveSupport = params.allowNonSeamlessAdaptiveness int requiredAdaptiveSupport = params.allowNonSeamlessAdaptiveness
? (RendererCapabilities.ADAPTIVE_NOT_SEAMLESS | RendererCapabilities.ADAPTIVE_SEAMLESS) ? (RendererCapabilities.ADAPTIVE_NOT_SEAMLESS | RendererCapabilities.ADAPTIVE_SEAMLESS)
...@@ -1381,7 +1385,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -1381,7 +1385,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
params.viewportOrientationMayChange); params.viewportOrientationMayChange);
if (adaptiveTracks.length > 0) { if (adaptiveTracks.length > 0) {
return Assertions.checkNotNull(adaptiveTrackSelectionFactory) return Assertions.checkNotNull(adaptiveTrackSelectionFactory)
.createTrackSelection(group, adaptiveTracks); .createTrackSelection(group, bandwidthMeter, adaptiveTracks);
} }
} }
return null; return null;
...@@ -1600,8 +1604,8 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -1600,8 +1604,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
getAdaptiveAudioTracks( getAdaptiveAudioTracks(
selectedGroup, formatSupports[selectedGroupIndex], params.allowMixedMimeAdaptiveness); selectedGroup, formatSupports[selectedGroupIndex], params.allowMixedMimeAdaptiveness);
if (adaptiveTracks.length > 0) { if (adaptiveTracks.length > 0) {
return adaptiveTrackSelectionFactory.createTrackSelection(selectedGroup, return adaptiveTrackSelectionFactory
adaptiveTracks); .createTrackSelection(selectedGroup, getBandwidthMeter(), adaptiveTracks);
} }
} }
return new FixedTrackSelection(selectedGroup, selectedTrackIndex); return new FixedTrackSelection(selectedGroup, selectedTrackIndex);
......
...@@ -18,6 +18,7 @@ package com.google.android.exoplayer2.trackselection; ...@@ -18,6 +18,7 @@ package com.google.android.exoplayer2.trackselection;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.source.TrackGroup; import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.upstream.BandwidthMeter;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
/** /**
...@@ -48,7 +49,8 @@ public final class FixedTrackSelection extends BaseTrackSelection { ...@@ -48,7 +49,8 @@ public final class FixedTrackSelection extends BaseTrackSelection {
} }
@Override @Override
public FixedTrackSelection createTrackSelection(TrackGroup group, int... tracks) { public FixedTrackSelection createTrackSelection(
TrackGroup group, @Nullable BandwidthMeter bandwidthMeter, int... tracks) {
Assertions.checkArgument(tracks.length == 1); Assertions.checkArgument(tracks.length == 1);
return new FixedTrackSelection(group, tracks[0], reason, data); return new FixedTrackSelection(group, tracks[0], reason, data);
} }
......
...@@ -19,6 +19,7 @@ import android.os.SystemClock; ...@@ -19,6 +19,7 @@ import android.os.SystemClock;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.source.TrackGroup; import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.upstream.BandwidthMeter;
import java.util.Random; import java.util.Random;
/** /**
...@@ -45,7 +46,8 @@ public final class RandomTrackSelection extends BaseTrackSelection { ...@@ -45,7 +46,8 @@ public final class RandomTrackSelection extends BaseTrackSelection {
} }
@Override @Override
public RandomTrackSelection createTrackSelection(TrackGroup group, int... tracks) { public RandomTrackSelection createTrackSelection(
TrackGroup group, @Nullable BandwidthMeter bandwidthMeter, int... tracks) {
return new RandomTrackSelection(group, tracks, random); return new RandomTrackSelection(group, tracks, random);
} }
} }
......
...@@ -20,6 +20,7 @@ import com.google.android.exoplayer2.C; ...@@ -20,6 +20,7 @@ import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.source.TrackGroup; import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.source.chunk.MediaChunk; import com.google.android.exoplayer2.source.chunk.MediaChunk;
import com.google.android.exoplayer2.upstream.BandwidthMeter;
import java.util.List; import java.util.List;
/** /**
...@@ -37,15 +38,28 @@ public interface TrackSelection { ...@@ -37,15 +38,28 @@ public interface TrackSelection {
interface Factory { 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. * Creates a new selection.
* *
* @param group The {@link TrackGroup}. Must not be null. * @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 * @param tracks The indices of the selected tracks within the {@link TrackGroup}. Must not be
* null or empty. May be in any order. * null or empty. May be in any order.
* @return The created selection. * @return The created selection.
*/ */
TrackSelection createTrackSelection(TrackGroup group, int... tracks); default TrackSelection createTrackSelection(
TrackGroup group, @Nullable BandwidthMeter bandwidthMeter, int... tracks) {
return createTrackSelection(group, tracks);
}
} }
/** /**
......
...@@ -22,6 +22,7 @@ import com.google.android.exoplayer2.Renderer; ...@@ -22,6 +22,7 @@ import com.google.android.exoplayer2.Renderer;
import com.google.android.exoplayer2.RendererCapabilities; import com.google.android.exoplayer2.RendererCapabilities;
import com.google.android.exoplayer2.RendererConfiguration; import com.google.android.exoplayer2.RendererConfiguration;
import com.google.android.exoplayer2.source.TrackGroupArray; 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 * 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; ...@@ -29,48 +30,52 @@ import com.google.android.exoplayer2.source.TrackGroupArray;
* suitable for most use cases. * suitable for most use cases.
* *
* <h3>Interactions with the player</h3> * <h3>Interactions with the player</h3>
*
* The following interactions occur between the player and its track selector during playback. * The following interactions occur between the player and its track selector during playback.
*
* <p> * <p>
*
* <ul> * <ul>
* <li>When the player is created it will initialize the track selector by calling * <li>When the player is created it will initialize the track selector by calling {@link
* {@link #init(InvalidationListener)}.</li> * #init(InvalidationListener, BandwidthMeter)}.
* <li>When the player needs to make a track selection it will call * <li>When the player needs to make a track selection it will call {@link
* {@link #selectTracks(RendererCapabilities[], TrackGroupArray)}. This typically occurs at the * #selectTracks(RendererCapabilities[], TrackGroupArray)}. This typically occurs at the start
* start of playback, when the player starts to buffer a new period of the media being played, * of playback, when the player starts to buffer a new period of the media being played, and
* and when the track selector invalidates its previous selections.</li> * when the track selector invalidates its previous selections.
* <li>The player may perform a track selection well in advance of the selected tracks becoming * <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 * 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 * 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 * 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 * 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 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 * selection may never become active, for example if the user seeks to some other period of
* media during the 30 second gap. The player indicates to the track selector when a selection * the media during the 30 second gap. The player indicates to the track selector when a
* it has previously made becomes active by calling {@link #onSelectionActivated(Object)}.</li> * 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 * <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 * made are invalid, it can do so by calling {@link
* {@link InvalidationListener#onTrackSelectionsInvalidated()} on the * InvalidationListener#onTrackSelectionsInvalidated()} on the {@link InvalidationListener}
* {@link InvalidationListener} that was passed to {@link #init(InvalidationListener)}. A * that was passed to {@link #init(InvalidationListener, BandwidthMeter)}. A track selector
* track selector may wish to do this if its configuration has changed, for example if it now * may wish to do this if its configuration has changed, for example if it now wishes to
* wishes to prefer audio tracks in a particular language. This will trigger the player to make * prefer audio tracks in a particular language. This will trigger the player to make new
* new track selections. Note that the player will have to re-buffer in the case that the 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. * track selection for the currently playing period differs from the one that was invalidated.
* </li>
* </ul> * </ul>
* *
* <h3>Renderer configuration</h3> * <h3>Renderer configuration</h3>
* The {@link TrackSelectorResult} returned by *
* {@link #selectTracks(RendererCapabilities[], TrackGroupArray)} contains not only * The {@link TrackSelectorResult} returned by {@link #selectTracks(RendererCapabilities[],
* {@link TrackSelection}s for each renderer, but also {@link RendererConfiguration}s defining * TrackGroupArray)} contains not only {@link TrackSelection}s for each renderer, but also {@link
* configuration parameters that the renderers should apply when consuming the corresponding media. * RendererConfiguration}s defining configuration parameters that the renderers should apply when
* Whilst it may seem counter-intuitive for a track selector to also specify renderer configuration * consuming the corresponding media. Whilst it may seem counter-intuitive for a track selector to
* information, in practice the two are tightly bound together. It may only be possible to play a * also specify renderer configuration information, in practice the two are tightly bound together.
* certain combination tracks if the renderers are configured in a particular way. Equally, it may * It may only be possible to play a certain combination tracks if the renderers are configured in a
* only be possible to configure renderers in a particular way if certain tracks are selected. Hence * particular way. Equally, it may only be possible to configure renderers in a particular way if
* it makes sense to determined the track selection and corresponding renderer configurations in a * certain tracks are selected. Hence it makes sense to determined the track selection and
* single step. * corresponding renderer configurations in a single step.
* *
* <h3>Threading model</h3> * <h3>Threading model</h3>
*
* All calls made by the player into the track selector are on the player's internal playback * 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()} * thread. The track selector may call {@link InvalidationListener#onTrackSelectionsInvalidated()}
* from any thread. * from any thread.
...@@ -91,15 +96,19 @@ public abstract class TrackSelector { ...@@ -91,15 +96,19 @@ public abstract class TrackSelector {
} }
private @Nullable InvalidationListener listener; private @Nullable InvalidationListener listener;
private @Nullable BandwidthMeter bandwidthMeter;
/** /**
* Called by the player to initialize the selector. * Called by the player to initialize the selector.
* *
* @param listener An invalidation listener that the selector can call to indicate that selections * @param listener An invalidation listener that the selector can call to indicate that selections
* it has previously made are no longer valid. * 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.listener = listener;
this.bandwidthMeter = bandwidthMeter;
} }
/** /**
...@@ -132,4 +141,11 @@ public abstract class TrackSelector { ...@@ -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;
}
} }
...@@ -16,6 +16,10 @@ ...@@ -16,6 +16,10 @@
package com.google.android.exoplayer2.trackselection; package com.google.android.exoplayer2.trackselection;
import static com.google.common.truth.Truth.assertThat; 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.Mockito.when;
import static org.mockito.MockitoAnnotations.initMocks; import static org.mockito.MockitoAnnotations.initMocks;
...@@ -55,6 +59,23 @@ public final class AdaptiveTrackSelectionTest { ...@@ -55,6 +59,23 @@ public final class AdaptiveTrackSelectionTest {
} }
@Test @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() { public void testSelectInitialIndexUseMaxInitialBitrateIfNoBandwidthEstimate() {
Format format1 = videoFormat(/* bitrate= */ 500, /* width= */ 320, /* height= */ 240); Format format1 = videoFormat(/* bitrate= */ 500, /* width= */ 320, /* height= */ 240);
Format format2 = videoFormat(/* bitrate= */ 1000, /* width= */ 640, /* height= */ 480); Format format2 = videoFormat(/* bitrate= */ 1000, /* width= */ 640, /* height= */ 480);
......
...@@ -19,9 +19,13 @@ import static com.google.android.exoplayer2.RendererCapabilities.FORMAT_EXCEEDS_ ...@@ -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.RendererCapabilities.FORMAT_HANDLED;
import static com.google.android.exoplayer2.RendererConfiguration.DEFAULT; import static com.google.android.exoplayer2.RendererConfiguration.DEFAULT;
import static com.google.common.truth.Truth.assertThat; 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.never;
import static org.mockito.Mockito.times; import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.initMocks; import static org.mockito.MockitoAnnotations.initMocks;
import android.os.Parcel; import android.os.Parcel;
...@@ -38,6 +42,7 @@ import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.Paramet ...@@ -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.ParametersBuilder;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.SelectionOverride; import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.SelectionOverride;
import com.google.android.exoplayer2.trackselection.TrackSelector.InvalidationListener; import com.google.android.exoplayer2.trackselection.TrackSelector.InvalidationListener;
import com.google.android.exoplayer2.upstream.BandwidthMeter;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
...@@ -71,8 +76,7 @@ public final class DefaultTrackSelectorTest { ...@@ -71,8 +76,7 @@ public final class DefaultTrackSelectorTest {
private static final RendererCapabilities[] RENDERER_CAPABILITIES_WITH_NO_SAMPLE_RENDERER = private static final RendererCapabilities[] RENDERER_CAPABILITIES_WITH_NO_SAMPLE_RENDERER =
new RendererCapabilities[] {VIDEO_CAPABILITIES, NO_SAMPLE_CAPABILITIES}; new RendererCapabilities[] {VIDEO_CAPABILITIES, NO_SAMPLE_CAPABILITIES};
private static final TrackGroup VIDEO_TRACK_GROUP = private static final Format VIDEO_FORMAT =
new TrackGroup(
Format.createVideoSampleFormat( Format.createVideoSampleFormat(
"video", "video",
MimeTypes.VIDEO_H264, MimeTypes.VIDEO_H264,
...@@ -83,9 +87,8 @@ public final class DefaultTrackSelectorTest { ...@@ -83,9 +87,8 @@ public final class DefaultTrackSelectorTest {
768, 768,
Format.NO_VALUE, Format.NO_VALUE,
null, null,
null)); null);
private static final TrackGroup AUDIO_TRACK_GROUP = private static final Format AUDIO_FORMAT =
new TrackGroup(
Format.createAudioSampleFormat( Format.createAudioSampleFormat(
"audio", "audio",
MimeTypes.AUDIO_AAC, MimeTypes.AUDIO_AAC,
...@@ -97,7 +100,9 @@ public final class DefaultTrackSelectorTest { ...@@ -97,7 +100,9 @@ public final class DefaultTrackSelectorTest {
null, null,
null, null,
0, 0,
null)); 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 = private static final TrackGroupArray TRACK_GROUPS =
new TrackGroupArray(VIDEO_TRACK_GROUP, AUDIO_TRACK_GROUP); new TrackGroupArray(VIDEO_TRACK_GROUP, AUDIO_TRACK_GROUP);
...@@ -282,7 +287,7 @@ public final class DefaultTrackSelectorTest { ...@@ -282,7 +287,7 @@ public final class DefaultTrackSelectorTest {
@Test @Test
public void testSetParameterWithDefaultParametersDoesNotNotifyInvalidationListener() public void testSetParameterWithDefaultParametersDoesNotNotifyInvalidationListener()
throws Exception { throws Exception {
trackSelector.init(invalidationListener); trackSelector.init(invalidationListener, /* bandwidthMeter= */ null);
verify(invalidationListener, never()).onTrackSelectionsInvalidated(); verify(invalidationListener, never()).onTrackSelectionsInvalidated();
} }
...@@ -295,7 +300,7 @@ public final class DefaultTrackSelectorTest { ...@@ -295,7 +300,7 @@ public final class DefaultTrackSelectorTest {
public void testSetParameterWithNonDefaultParameterNotifyInvalidationListener() public void testSetParameterWithNonDefaultParameterNotifyInvalidationListener()
throws Exception { throws Exception {
Parameters parameters = new ParametersBuilder().setPreferredAudioLanguage("eng").build(); Parameters parameters = new ParametersBuilder().setPreferredAudioLanguage("eng").build();
trackSelector.init(invalidationListener); trackSelector.init(invalidationListener, /* bandwidthMeter= */ null);
trackSelector.setParameters(parameters); trackSelector.setParameters(parameters);
verify(invalidationListener).onTrackSelectionsInvalidated(); verify(invalidationListener).onTrackSelectionsInvalidated();
...@@ -310,7 +315,7 @@ public final class DefaultTrackSelectorTest { ...@@ -310,7 +315,7 @@ public final class DefaultTrackSelectorTest {
public void testSetParameterWithSameParametersDoesNotNotifyInvalidationListenerAgain() public void testSetParameterWithSameParametersDoesNotNotifyInvalidationListenerAgain()
throws Exception { throws Exception {
ParametersBuilder builder = new ParametersBuilder().setPreferredAudioLanguage("eng"); ParametersBuilder builder = new ParametersBuilder().setPreferredAudioLanguage("eng");
trackSelector.init(invalidationListener); trackSelector.init(invalidationListener, /* bandwidthMeter= */ null);
trackSelector.setParameters(builder.build()); trackSelector.setParameters(builder.build());
trackSelector.setParameters(builder.build()); trackSelector.setParameters(builder.build());
...@@ -956,6 +961,116 @@ public final class DefaultTrackSelectorTest { ...@@ -956,6 +961,116 @@ public final class DefaultTrackSelectorTest {
assertThat(result.selections.get(0).getSelectedFormat()).isEqualTo(lowerBitrateFormat); 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) { private static void assertTrackSelections(TrackSelectorResult result, TrackSelection[] expected) {
assertThat(result.length).isEqualTo(expected.length); assertThat(result.length).isEqualTo(expected.length);
for (int i = 0; i < expected.length; i++) { for (int i = 0; i < expected.length; i++) {
......
/*
* 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);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment