Commit 7d6b0e1f by olly Committed by Oliver Woodman

Move renderer flags, overrides and tunneling ID into Parameters

- This is needed to make DefaultTrackSelector properly thread
  safe, and enable atomic changes to the selector that, for
  example, disable a renderer and enable another one at the same
  time.

- This change also saves/restores parameters and the start
  position in PlayerActivity, resolving the ref'd issue.

Issue: #3915

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=193913350
parent 5926e201
......@@ -116,6 +116,12 @@ public class PlayerActivity extends Activity
// For backwards compatibility only.
private static final String DRM_SCHEME_UUID_EXTRA = "drm_scheme_uuid";
// Saved instance state keys.
private static final String KEY_TRACK_SELECTOR_PARAMETERS = "track_selector_parameters";
private static final String KEY_WINDOW = "window";
private static final String KEY_POSITION = "position";
private static final String KEY_AUTO_PLAY = "auto_play";
private static final DefaultBandwidthMeter BANDWIDTH_METER = new DefaultBandwidthMeter();
private static final CookieManager DEFAULT_COOKIE_MANAGER;
static {
......@@ -132,14 +138,15 @@ public class PlayerActivity extends Activity
private SimpleExoPlayer player;
private MediaSource mediaSource;
private DefaultTrackSelector trackSelector;
private DefaultTrackSelector.Parameters trackSelectorParameters;
private TrackSelectionHelper trackSelectionHelper;
private DebugTextViewHelper debugViewHelper;
private boolean inErrorState;
private TrackGroupArray lastSeenTrackGroupArray;
private boolean shouldAutoPlay;
private int resumeWindow;
private long resumePosition;
private boolean startAutoPlay;
private int startWindow;
private long startPosition;
// Fields used only for ad playback. The ads loader is loaded via reflection.
......@@ -152,8 +159,6 @@ public class PlayerActivity extends Activity
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
shouldAutoPlay = true;
clearResumePosition();
mediaDataSourceFactory = buildDataSourceFactory(true);
mainHandler = new Handler();
if (CookieHandler.getDefault() != DEFAULT_COOKIE_MANAGER) {
......@@ -169,13 +174,22 @@ public class PlayerActivity extends Activity
playerView = findViewById(R.id.player_view);
playerView.setControllerVisibilityListener(this);
playerView.requestFocus();
if (savedInstanceState != null) {
trackSelectorParameters = savedInstanceState.getParcelable(KEY_TRACK_SELECTOR_PARAMETERS);
startAutoPlay = savedInstanceState.getBoolean(KEY_AUTO_PLAY);
startWindow = savedInstanceState.getInt(KEY_WINDOW);
startPosition = savedInstanceState.getLong(KEY_POSITION);
} else {
trackSelectorParameters = new DefaultTrackSelector.ParametersBuilder().build();
clearStartPosition();
}
}
@Override
public void onNewIntent(Intent intent) {
releasePlayer();
shouldAutoPlay = true;
clearResumePosition();
clearStartPosition();
setIntent(intent);
}
......@@ -233,6 +247,16 @@ public class PlayerActivity extends Activity
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
updateTrackSelectorParameters();
updateStartPosition();
outState.putParcelable(KEY_TRACK_SELECTOR_PARAMETERS, trackSelectorParameters);
outState.putBoolean(KEY_AUTO_PLAY, startAutoPlay);
outState.putInt(KEY_WINDOW, startWindow);
outState.putLong(KEY_POSITION, startPosition);
}
// Activity input
@Override
......@@ -365,6 +389,7 @@ public class PlayerActivity extends Activity
new DefaultRenderersFactory(this, extensionRendererMode);
trackSelector = new DefaultTrackSelector(trackSelectionFactory);
trackSelector.setParameters(trackSelectorParameters);
trackSelectionHelper = new TrackSelectionHelper(trackSelector);
lastSeenTrackGroupArray = null;
......@@ -381,7 +406,7 @@ public class PlayerActivity extends Activity
drmSessionManager.addListener(mainHandler, eventLogger);
}
player.setPlayWhenReady(shouldAutoPlay);
player.setPlayWhenReady(startAutoPlay);
playerView.setPlayer(player);
playerView.setPlaybackPreparer(this);
debugViewHelper = new DebugTextViewHelper(player, debugTextView);
......@@ -421,11 +446,11 @@ public class PlayerActivity extends Activity
}
mediaSource.addEventListener(mainHandler, eventLogger);
}
boolean haveResumePosition = resumeWindow != C.INDEX_UNSET;
if (haveResumePosition) {
player.seekTo(resumeWindow, resumePosition);
boolean haveStartPosition = startWindow != C.INDEX_UNSET;
if (haveStartPosition) {
player.seekTo(startWindow, startPosition);
}
player.prepare(mediaSource, !haveResumePosition, false);
player.prepare(mediaSource, !haveStartPosition, false);
inErrorState = false;
updateButtonVisibilities();
}
......@@ -483,10 +508,10 @@ public class PlayerActivity extends Activity
private void releasePlayer() {
if (player != null) {
updateTrackSelectorParameters();
updateStartPosition();
debugViewHelper.stop();
debugViewHelper = null;
shouldAutoPlay = player.getPlayWhenReady();
updateResumePosition();
player.release();
player = null;
mediaSource = null;
......@@ -495,14 +520,24 @@ public class PlayerActivity extends Activity
}
}
private void updateResumePosition() {
resumeWindow = player.getCurrentWindowIndex();
resumePosition = Math.max(0, player.getContentPosition());
private void updateTrackSelectorParameters() {
if (trackSelector != null) {
trackSelectorParameters = trackSelector.getParameters();
}
}
private void updateStartPosition() {
if (player != null) {
startAutoPlay = player.getPlayWhenReady();
startWindow = player.getCurrentWindowIndex();
startPosition = Math.max(0, player.getContentPosition());
}
}
private void clearResumePosition() {
resumeWindow = C.INDEX_UNSET;
resumePosition = C.TIME_UNSET;
private void clearStartPosition() {
startAutoPlay = true;
startWindow = C.INDEX_UNSET;
startPosition = C.TIME_UNSET;
}
/**
......@@ -661,7 +696,7 @@ public class PlayerActivity extends Activity
// This will only occur if the user has performed a seek whilst in the error state. Update
// the resume position so that if the user then retries, playback will resume from the
// position to which they seeked.
updateResumePosition();
updateStartPosition();
}
}
......@@ -695,10 +730,10 @@ public class PlayerActivity extends Activity
}
inErrorState = true;
if (isBehindLiveWindow(e)) {
clearResumePosition();
clearStartPosition();
initializePlayer();
} else {
updateResumePosition();
updateStartPosition();
updateButtonVisibilities();
showControls();
}
......
......@@ -30,6 +30,8 @@ import com.google.android.exoplayer2.RendererCapabilities;
import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.Parameters;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.ParametersBuilder;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.SelectionOverride;
import com.google.android.exoplayer2.trackselection.MappingTrackSelector.MappedTrackInfo;
import java.util.Arrays;
......@@ -79,8 +81,9 @@ import java.util.Arrays;
!= RendererCapabilities.ADAPTIVE_NOT_SUPPORTED
&& trackGroups.get(i).length > 1;
}
isDisabled = selector.getRendererDisabled(rendererIndex);
override = selector.getSelectionOverride(rendererIndex, trackGroups);
Parameters parameters = selector.getParameters();
isDisabled = parameters.getRendererDisabled(rendererIndex);
override = parameters.getSelectionOverride(rendererIndex, trackGroups);
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
builder.setTitle(title)
......@@ -170,12 +173,14 @@ import java.util.Arrays;
@Override
public void onClick(DialogInterface dialog, int which) {
selector.setRendererDisabled(rendererIndex, isDisabled);
ParametersBuilder parametersBuilder = selector.buildUponParameters();
parametersBuilder.setRendererDisabled(rendererIndex, isDisabled);
if (override != null) {
selector.setSelectionOverride(rendererIndex, trackGroups, override);
parametersBuilder.setSelectionOverride(rendererIndex, trackGroups, override);
} else {
selector.clearSelectionOverrides(rendererIndex);
parametersBuilder.clearSelectionOverrides(rendererIndex);
}
selector.setParameters(parametersBuilder);
}
// View.OnClickListener
......
......@@ -45,42 +45,47 @@ import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
/**
* A default {@link TrackSelector} suitable for most use cases.
* A default {@link TrackSelector} suitable for most use cases. Track selections are made according
* to configurable {@link Parameters}, which can be set by calling {@link
* #setParameters(Parameters)}.
*
* <h3>Constraint based track selection</h3>
* <h3>Modifying parameters</h3>
*
* Whilst this selector supports setting specific track overrides, the recommended way of changing
* which tracks are selected is by setting {@link Parameters} that constrain the track selection
* process. For example an instance can specify a preferred language for the audio track, and impose
* constraints on the maximum video resolution that should be selected for adaptive playbacks.
* Modifying the parameters is simple:
* To modify only some aspects of the parameters currently used by a selector, it's possible to
* obtain a {@link ParametersBuilder} initialized with the current {@link Parameters}. The desired
* modifications can be made on the builder, and the resulting {@link Parameters} can then be built
* and set on the selector. For example the following code modifies the parameters to restrict video
* track selections to SD, and to prefer German audio tracks:
*
* <pre>{@code
* // Build on the current parameters.
* Parameters currentParameters = trackSelector.getParameters();
* // Generate new parameters to prefer German audio and impose a maximum video size constraint.
* // Build the resulting parameters.
* Parameters newParameters = currentParameters
* .withPreferredAudioLanguage("deu")
* .withMaxVideoSize(1024, 768);
* // Set the new parameters on the selector.
* .buildUpon()
* .setMaxVideoSizeSd()
* .setPreferredAudioLanguage("deu")
* .build();
* // Set the new parameters.
* trackSelector.setParameters(newParameters);
* }</pre>
*
* There are several benefits to using constraint based track selection instead of specific track
* overrides:
* Convenience methods and chaining allow this to be written more concisely as:
*
* <ul>
* <li>You can specify constraints before knowing what tracks the media provides. This can
* simplify track selection code (e.g. you don't have to listen for changes in the available
* tracks before configuring the selector).
* <li>Constraints can be applied consistently across all periods in a complex piece of media,
* even if those periods contain different tracks. In contrast, a specific track override is
* only applied to periods whose tracks match those for which the override was set.
* </ul>
* <pre>{@code
* trackSelector.setParameters(
* trackSelector
* .buildUponParameters()
* .setMaxVideoSizeSd()
* .setPreferredAudioLanguage("deu"));
* }</pre>
*
* Selection {@link Parameters} support many different options, some of which are described below.
*
* <h3>Track overrides</h3>
* <h3>Track selection overrides</h3>
*
* This selector supports overriding of track selections for each renderer. To specify an override
* for a renderer it's first necessary to obtain the tracks that have been mapped to it:
* Track selection overrides can be used to select specific tracks. To specify an override for a
* renderer, it's first necessary to obtain the tracks that have been mapped to it:
*
* <pre>{@code
* MappedTrackInfo mappedTrackInfo = trackSelector.getCurrentMappedTrackInfo();
......@@ -92,31 +97,58 @@ import java.util.concurrent.atomic.AtomicReference;
* setting an override isn't possible. Note that a {@link Player.EventListener} registered on the
* player can be used to determine when the current tracks (and therefore the mapping) changes. If
* {@code rendererTrackGroups} is non-null then an override can be set. The next step is to query
* the properties of the available tracks to determine the {@code groupIndex} of the track group you
* want to select and the {@code trackIndices} within it. You can then create and set the override:
* the properties of the available tracks to determine the {@code groupIndex} and the {@code
* trackIndices} within the group it that should be selected. The override can then be specified
* using {@link ParametersBuilder#setSelectionOverride}:
*
* <pre>{@code
* trackSelector.setSelectionOverride(rendererIndex, rendererTrackGroups,
* new SelectionOverride(groupIndex, trackIndices));
* SelectionOverride selectionOverride = new SelectionOverride(groupIndex, trackIndices);
* trackSelector.setParameters(
* trackSelector
* .buildUponParameters()
* .setSelectionOverride(rendererIndex, rendererTrackGroups, selectionOverride));
* }</pre>
*
* If the override is {@code null} then no tracks will be selected.
* <h3>Disabling renderers</h3>
*
* Renderers can be disabled using {@link ParametersBuilder#setRendererDisabled}. Disabling a
* renderer differs from setting a {@code null} override because the renderer is disabled
* unconditionally, whereas a {@code null} override is applied only when the track groups available
* to the renderer match the {@link TrackGroupArray} for which it was specified.
*
* <p>Note that an override applies only when the track groups available to the renderer match the
* {@link TrackGroupArray} for which the override was specified. Overrides can be cleared using the
* {@code clearSelectionOverride} methods.
* <h3>Constraint based track selection</h3>
*
* <h3>Disabling renderers</h3>
* Whilst track selection overrides make it possible to select specific tracks, the recommended way
* of controlling which tracks are selected is by specifying constraints. For example consider the
* case of wanting to restrict video track selections to SD, and preferring German audio tracks.
* Track selection overrides could be used to select specific tracks meeting these criteria, however
* a simpler and more flexible approach is to specify these constraints directly:
*
* Renderers can be disabled using {@link #setRendererDisabled(int, boolean)}. Disabling a renderer
* differs from setting a {@code null} override because the renderer is disabled unconditionally,
* whereas a {@code null} override is applied only when the track groups available to the renderer
* match the {@link TrackGroupArray} for which it was specified.
* <pre>{@code
* trackSelector.setParameters(
* trackSelector
* .buildUponParameters()
* .setMaxVideoSizeSd()
* .setPreferredAudioLanguage("deu"));
* }</pre>
*
* There are several benefits to using constraint based track selection instead of specific track
* overrides:
*
* <ul>
* <li>You can specify constraints before knowing what tracks the media provides. This can
* simplify track selection code (e.g. you don't have to listen for changes in the available
* tracks before configuring the selector).
* <li>Constraints can be applied consistently across all periods in a complex piece of media,
* even if those periods contain different tracks. In contrast, a specific track override is
* only applied to periods whose tracks match those for which the override was set.
* </ul>
*
* <h3>Tunneling</h3>
*
* Tunneled playback can be enabled in cases where the combination of renderers and selected tracks
* support it. See {@link #setTunnelingAudioSessionId(int)} for more details.
* support it. Tunneled playback is enabled by passing an audio session ID to {@link
* ParametersBuilder#setTunnelingAudioSessionId(int)}.
*/
public class DefaultTrackSelector extends MappingTrackSelector {
......@@ -125,6 +157,9 @@ public class DefaultTrackSelector extends MappingTrackSelector {
*/
public static final class ParametersBuilder {
private final SparseArray<Map<TrackGroupArray, SelectionOverride>> selectionOverrides;
private final SparseBooleanArray rendererDisabledFlags;
private String preferredAudioLanguage;
private String preferredTextLanguage;
private boolean selectUndeterminedTextLanguage;
......@@ -140,6 +175,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
private int viewportWidth;
private int viewportHeight;
private boolean viewportOrientationMayChange;
private int tunnelingAudioSessionId;
/**
* Creates a builder obtaining the initial values from {@link Parameters#DEFAULT}.
......@@ -153,6 +189,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
* obtained.
*/
private ParametersBuilder(Parameters initialValues) {
selectionOverrides = initialValues.selectionOverrides.clone();
rendererDisabledFlags = initialValues.rendererDisabledFlags.clone();
preferredAudioLanguage = initialValues.preferredAudioLanguage;
preferredTextLanguage = initialValues.preferredTextLanguage;
selectUndeterminedTextLanguage = initialValues.selectUndeterminedTextLanguage;
......@@ -168,6 +206,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
viewportWidth = initialValues.viewportWidth;
viewportHeight = initialValues.viewportHeight;
viewportOrientationMayChange = initialValues.viewportOrientationMayChange;
tunnelingAudioSessionId = initialValues.tunnelingAudioSessionId;
}
/**
......@@ -343,10 +382,133 @@ public class DefaultTrackSelector extends MappingTrackSelector {
}
/**
* Sets whether the renderer at the specified index is disabled. Disabling a renderer prevents
* the selector from selecting any tracks for it.
*
* @param rendererIndex The renderer index.
* @param disabled Whether the renderer is disabled.
*/
public final ParametersBuilder setRendererDisabled(int rendererIndex, boolean disabled) {
if (rendererDisabledFlags.get(rendererIndex) == disabled) {
// The disabled flag is unchanged.
return this;
}
// Only true values are placed in the array to make it easier to check for equality.
if (disabled) {
rendererDisabledFlags.put(rendererIndex, true);
} else {
rendererDisabledFlags.delete(rendererIndex);
}
return this;
}
/**
* Overrides the track selection for the renderer at the specified index.
*
* <p>When the {@link TrackGroupArray} mapped to the renderer matches the one provided, the
* override is applied. When the {@link TrackGroupArray} does not match, the override has no
* effect. The override replaces any previous override for the specified {@link TrackGroupArray}
* for the specified {@link Renderer}.
*
* <p>Passing a {@code null} override will cause the renderer to be disabled when the {@link
* TrackGroupArray} mapped to it matches the one provided. When the {@link TrackGroupArray} does
* not match a {@code null} override has no effect. Hence a {@code null} override differs from
* disabling the renderer using {@link #setRendererDisabled(int, boolean)} because the renderer
* is disabled conditionally on the {@link TrackGroupArray} mapped to it, where-as {@link
* #setRendererDisabled(int, boolean)} disables the renderer unconditionally.
*
* <p>To remove overrides use {@link #clearSelectionOverride(int, TrackGroupArray)}, {@link
* #clearSelectionOverrides(int)} or {@link #clearSelectionOverrides()}.
*
* @param rendererIndex The renderer index.
* @param groups The {@link TrackGroupArray} for which the override should be applied.
* @param override The override.
*/
public final ParametersBuilder setSelectionOverride(
int rendererIndex, TrackGroupArray groups, SelectionOverride override) {
Map<TrackGroupArray, SelectionOverride> overrides = selectionOverrides.get(rendererIndex);
if (overrides == null) {
overrides = new HashMap<>();
selectionOverrides.put(rendererIndex, overrides);
}
if (overrides.containsKey(groups) && Util.areEqual(overrides.get(groups), override)) {
// The override is unchanged.
return this;
}
overrides.put(groups, override);
return this;
}
/**
* Clears a track selection override for the specified renderer and {@link TrackGroupArray}.
*
* @param rendererIndex The renderer index.
* @param groups The {@link TrackGroupArray} for which the override should be cleared.
*/
public final ParametersBuilder clearSelectionOverride(
int rendererIndex, TrackGroupArray groups) {
Map<TrackGroupArray, SelectionOverride> overrides = selectionOverrides.get(rendererIndex);
if (overrides == null || !overrides.containsKey(groups)) {
// Nothing to clear.
return this;
}
overrides.remove(groups);
if (overrides.isEmpty()) {
selectionOverrides.remove(rendererIndex);
}
return this;
}
/**
* Clears all track selection overrides for the specified renderer.
*
* @param rendererIndex The renderer index.
*/
public final ParametersBuilder clearSelectionOverrides(int rendererIndex) {
Map<TrackGroupArray, SelectionOverride> overrides = selectionOverrides.get(rendererIndex);
if (overrides == null || overrides.isEmpty()) {
// Nothing to clear.
return this;
}
selectionOverrides.remove(rendererIndex);
return this;
}
/** Clears all track selection overrides for all renderers. */
public final ParametersBuilder clearSelectionOverrides() {
if (selectionOverrides.size() == 0) {
// Nothing to clear.
return this;
}
selectionOverrides.clear();
return this;
}
/**
* Enables or disables tunneling. To enable tunneling, pass an audio session id to use when in
* tunneling mode. Session ids can be generated using {@link
* C#generateAudioSessionIdV21(Context)}. To disable tunneling pass {@link
* C#AUDIO_SESSION_ID_UNSET}. Tunneling will only be activated if it's both enabled and
* supported by the audio and video renderers for the selected tracks.
*
* @param tunnelingAudioSessionId The audio session id to use when tunneling, or {@link
* C#AUDIO_SESSION_ID_UNSET} to disable tunneling.
*/
public ParametersBuilder setTunnelingAudioSessionId(int tunnelingAudioSessionId) {
if (this.tunnelingAudioSessionId != tunnelingAudioSessionId) {
this.tunnelingAudioSessionId = tunnelingAudioSessionId;
return this;
}
return this;
}
/**
* Builds a {@link Parameters} instance with the selected values.
*/
public Parameters build() {
return new Parameters(
selectionOverrides,
rendererDisabledFlags,
preferredAudioLanguage,
preferredTextLanguage,
selectUndeterminedTextLanguage,
......@@ -361,7 +523,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
exceedRendererCapabilitiesIfNecessary,
viewportWidth,
viewportHeight,
viewportOrientationMayChange);
viewportOrientationMayChange,
tunnelingAudioSessionId);
}
}
......@@ -390,6 +553,11 @@ public class DefaultTrackSelector extends MappingTrackSelector {
*/
public static final Parameters DEFAULT = new Parameters();
// Per renderer overrides.
private final SparseArray<Map<TrackGroupArray, SelectionOverride>> selectionOverrides;
private final SparseBooleanArray rendererDisabledFlags;
// Audio
/**
* The preferred language for audio, as well as for forced text tracks, as an ISO 639-2/T tag.
......@@ -465,9 +633,16 @@ public class DefaultTrackSelector extends MappingTrackSelector {
* Whether to exceed renderer capabilities when no selection can be made otherwise.
*/
public final boolean exceedRendererCapabilitiesIfNecessary;
/**
* The audio session id to use when tunneling, or {@link C#AUDIO_SESSION_ID_UNSET} if tunneling
* is not to be enabled.
*/
public final int tunnelingAudioSessionId;
private Parameters() {
this(
new SparseArray<Map<TrackGroupArray, SelectionOverride>>(),
new SparseBooleanArray(),
null,
null,
false,
......@@ -482,10 +657,13 @@ public class DefaultTrackSelector extends MappingTrackSelector {
true,
Integer.MAX_VALUE,
Integer.MAX_VALUE,
true);
true,
C.AUDIO_SESSION_ID_UNSET);
}
/* package */ Parameters(
SparseArray<Map<TrackGroupArray, SelectionOverride>> selectionOverrides,
SparseBooleanArray rendererDisabledFlags,
String preferredAudioLanguage,
String preferredTextLanguage,
boolean selectUndeterminedTextLanguage,
......@@ -500,7 +678,10 @@ public class DefaultTrackSelector extends MappingTrackSelector {
boolean exceedRendererCapabilitiesIfNecessary,
int viewportWidth,
int viewportHeight,
boolean viewportOrientationMayChange) {
boolean viewportOrientationMayChange,
int tunnelingAudioSessionId) {
this.selectionOverrides = selectionOverrides;
this.rendererDisabledFlags = rendererDisabledFlags;
this.preferredAudioLanguage = Util.normalizeLanguageCode(preferredAudioLanguage);
this.preferredTextLanguage = Util.normalizeLanguageCode(preferredTextLanguage);
this.selectUndeterminedTextLanguage = selectUndeterminedTextLanguage;
......@@ -516,9 +697,12 @@ public class DefaultTrackSelector extends MappingTrackSelector {
this.viewportWidth = viewportWidth;
this.viewportHeight = viewportHeight;
this.viewportOrientationMayChange = viewportOrientationMayChange;
this.tunnelingAudioSessionId = tunnelingAudioSessionId;
}
/* package */ Parameters(Parcel in) {
this.selectionOverrides = readSelectionOverrides(in);
this.rendererDisabledFlags = in.readSparseBooleanArray();
this.preferredAudioLanguage = in.readString();
this.preferredTextLanguage = in.readString();
this.selectUndeterminedTextLanguage = Util.readBoolean(in);
......@@ -534,6 +718,41 @@ public class DefaultTrackSelector extends MappingTrackSelector {
this.viewportWidth = in.readInt();
this.viewportHeight = in.readInt();
this.viewportOrientationMayChange = Util.readBoolean(in);
this.tunnelingAudioSessionId = in.readInt();
}
/**
* Returns whether the renderer is disabled.
*
* @param rendererIndex The renderer index.
* @return Whether the renderer is disabled.
*/
public final boolean getRendererDisabled(int rendererIndex) {
return rendererDisabledFlags.get(rendererIndex);
}
/**
* Returns whether there is an override for the specified renderer and {@link TrackGroupArray}.
*
* @param rendererIndex The renderer index.
* @param groups The {@link TrackGroupArray}.
* @return Whether there is an override.
*/
public final boolean hasSelectionOverride(int rendererIndex, TrackGroupArray groups) {
Map<TrackGroupArray, SelectionOverride> overrides = selectionOverrides.get(rendererIndex);
return overrides != null && overrides.containsKey(groups);
}
/**
* Returns the override for the specified renderer and {@link TrackGroupArray}.
*
* @param rendererIndex The renderer index.
* @param groups The {@link TrackGroupArray}.
* @return The override, or null if no override exists.
*/
public final SelectionOverride getSelectionOverride(int rendererIndex, TrackGroupArray groups) {
Map<TrackGroupArray, SelectionOverride> overrides = selectionOverrides.get(rendererIndex);
return overrides != null ? overrides.get(groups) : null;
}
/**
......@@ -565,8 +784,11 @@ public class DefaultTrackSelector extends MappingTrackSelector {
&& viewportWidth == other.viewportWidth
&& viewportHeight == other.viewportHeight
&& maxVideoBitrate == other.maxVideoBitrate
&& tunnelingAudioSessionId == other.tunnelingAudioSessionId
&& TextUtils.equals(preferredAudioLanguage, other.preferredAudioLanguage)
&& TextUtils.equals(preferredTextLanguage, other.preferredTextLanguage);
&& TextUtils.equals(preferredTextLanguage, other.preferredTextLanguage)
&& areRendererDisabledFlagsEqual(rendererDisabledFlags, other.rendererDisabledFlags)
&& areSelectionOverridesEqual(selectionOverrides, other.selectionOverrides);
}
@Override
......@@ -584,6 +806,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
result = 31 * result + viewportWidth;
result = 31 * result + viewportHeight;
result = 31 * result + maxVideoBitrate;
result = 31 * result + tunnelingAudioSessionId;
result = 31 * result + preferredAudioLanguage.hashCode();
result = 31 * result + preferredTextLanguage.hashCode();
return result;
......@@ -598,6 +821,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
@Override
public void writeToParcel(Parcel dest, int flags) {
writeSelectionOverridesToParcel(dest, selectionOverrides);
dest.writeSparseBooleanArray(rendererDisabledFlags);
dest.writeString(preferredAudioLanguage);
dest.writeString(preferredTextLanguage);
Util.writeBoolean(dest, selectUndeterminedTextLanguage);
......@@ -613,6 +838,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
dest.writeInt(viewportWidth);
dest.writeInt(viewportHeight);
Util.writeBoolean(dest, viewportOrientationMayChange);
dest.writeInt(tunnelingAudioSessionId);
}
public static final Parcelable.Creator<Parameters> CREATOR =
......@@ -628,6 +854,93 @@ public class DefaultTrackSelector extends MappingTrackSelector {
return new Parameters[size];
}
};
// Static utility methods.
private static SparseArray<Map<TrackGroupArray, SelectionOverride>> readSelectionOverrides(
Parcel in) {
int renderersWithOverridesCount = in.readInt();
SparseArray<Map<TrackGroupArray, SelectionOverride>> selectionOverrides =
new SparseArray<>(renderersWithOverridesCount);
for (int i = 0; i < renderersWithOverridesCount; i++) {
int rendererIndex = in.readInt();
int overrideCount = in.readInt();
Map<TrackGroupArray, SelectionOverride> overrides = new HashMap<>(overrideCount);
for (int j = 0; j < overrideCount; j++) {
TrackGroupArray trackGroups = in.readParcelable(TrackGroupArray.class.getClassLoader());
SelectionOverride override = in.readParcelable(SelectionOverride.class.getClassLoader());
overrides.put(trackGroups, override);
}
selectionOverrides.put(rendererIndex, overrides);
}
return selectionOverrides;
}
private static void writeSelectionOverridesToParcel(
Parcel dest, SparseArray<Map<TrackGroupArray, SelectionOverride>> selectionOverrides) {
int renderersWithOverridesCount = selectionOverrides.size();
dest.writeInt(renderersWithOverridesCount);
for (int i = 0; i < renderersWithOverridesCount; i++) {
int rendererIndex = selectionOverrides.keyAt(i);
Map<TrackGroupArray, SelectionOverride> overrides = selectionOverrides.valueAt(i);
int overrideCount = overrides.size();
dest.writeInt(rendererIndex);
dest.writeInt(overrideCount);
for (Map.Entry<TrackGroupArray, SelectionOverride> override : overrides.entrySet()) {
dest.writeParcelable(override.getKey(), /* parcelableFlags= */ 0);
dest.writeParcelable(override.getValue(), /* parcelableFlags= */ 0);
}
}
}
private static boolean areRendererDisabledFlagsEqual(
SparseBooleanArray first, SparseBooleanArray second) {
int firstSize = first.size();
if (second.size() != firstSize) {
return false;
}
// Only true values are put into rendererDisabledFlags, so we don't need to compare values.
for (int indexInFirst = 0; indexInFirst < firstSize; indexInFirst++) {
if (second.indexOfKey(first.keyAt(indexInFirst)) < 0) {
return false;
}
}
return true;
}
private static boolean areSelectionOverridesEqual(
SparseArray<Map<TrackGroupArray, SelectionOverride>> first,
SparseArray<Map<TrackGroupArray, SelectionOverride>> second) {
int firstSize = first.size();
if (second.size() != firstSize) {
return false;
}
for (int indexInFirst = 0; indexInFirst < firstSize; indexInFirst++) {
int indexInSecond = second.indexOfKey(first.keyAt(indexInFirst));
if (indexInSecond < 0
|| !areSelectionOverridesEqual(
first.valueAt(indexInFirst), second.valueAt(indexInSecond))) {
return false;
}
}
return true;
}
private static boolean areSelectionOverridesEqual(
Map<TrackGroupArray, SelectionOverride> first,
Map<TrackGroupArray, SelectionOverride> second) {
int firstSize = first.size();
if (second.size() != firstSize) {
return false;
}
for (Map.Entry<TrackGroupArray, SelectionOverride> firstEntry : first.entrySet()) {
TrackGroupArray key = firstEntry.getKey();
if (!second.containsKey(key) || !Util.areEqual(firstEntry.getValue(), second.get(key))) {
return false;
}
}
return true;
}
}
/** A track selection override. */
......@@ -720,11 +1033,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
private static final int WITHIN_RENDERER_CAPABILITIES_BONUS = 1000;
private final TrackSelection.Factory adaptiveTrackSelectionFactory;
private final AtomicReference<Parameters> paramsReference;
private final SparseArray<Map<TrackGroupArray, SelectionOverride>> selectionOverrides;
private final SparseBooleanArray rendererDisabledFlags;
private int tunnelingAudioSessionId;
private final AtomicReference<Parameters> parametersReference;
/**
* Constructs an instance that does not support adaptive track selection.
......@@ -752,179 +1061,100 @@ public class DefaultTrackSelector extends MappingTrackSelector {
*/
public DefaultTrackSelector(TrackSelection.Factory adaptiveTrackSelectionFactory) {
this.adaptiveTrackSelectionFactory = adaptiveTrackSelectionFactory;
paramsReference = new AtomicReference<>(Parameters.DEFAULT);
selectionOverrides = new SparseArray<>();
rendererDisabledFlags = new SparseBooleanArray();
tunnelingAudioSessionId = C.AUDIO_SESSION_ID_UNSET;
parametersReference = new AtomicReference<>(Parameters.DEFAULT);
}
/**
* Atomically sets the provided parameters for track selection.
*
* @param params The parameters for track selection.
* @param parameters The parameters for track selection.
*/
public void setParameters(Parameters params) {
Assertions.checkNotNull(params);
if (!paramsReference.getAndSet(params).equals(params)) {
public void setParameters(Parameters parameters) {
Assertions.checkNotNull(parameters);
if (!parametersReference.getAndSet(parameters).equals(parameters)) {
invalidate();
}
}
/**
* Gets the current selection parameters.
* Atomically sets the provided parameters for track selection.
*
* @return The current selection parameters.
* @param parametersBuilder A builder from which to obtain the parameters for track selection.
*/
public Parameters getParameters() {
return paramsReference.get();
public void setParameters(ParametersBuilder parametersBuilder) {
setParameters(parametersBuilder.build());
}
/**
* Sets whether the renderer at the specified index is disabled. Disabling a renderer prevents the
* selector from selecting any tracks for it.
* Gets the current selection parameters.
*
* @param rendererIndex The renderer index.
* @param disabled Whether the renderer is disabled.
* @return The current selection parameters.
*/
public Parameters getParameters() {
return parametersReference.get();
}
/** Returns a new {@link ParametersBuilder} initialized with the current selection parameters. */
public ParametersBuilder buildUponParameters() {
return getParameters().buildUpon();
}
/** @deprecated Use {@link ParametersBuilder#setRendererDisabled(int, boolean)}. */
@Deprecated
public final void setRendererDisabled(int rendererIndex, boolean disabled) {
if (rendererDisabledFlags.get(rendererIndex) == disabled) {
// The disabled flag is unchanged.
return;
}
rendererDisabledFlags.put(rendererIndex, disabled);
invalidate();
setParameters(buildUponParameters().setRendererDisabled(rendererIndex, disabled));
}
/**
* Returns whether the renderer is disabled.
*
* @param rendererIndex The renderer index.
* @return Whether the renderer is disabled.
*/
/** @deprecated Use {@link Parameters#getRendererDisabled(int)}. * */
@Deprecated
public final boolean getRendererDisabled(int rendererIndex) {
return rendererDisabledFlags.get(rendererIndex);
return getParameters().getRendererDisabled(rendererIndex);
}
/**
* Overrides the track selection for the renderer at the specified index.
*
* <p>When the {@link TrackGroupArray} mapped to the renderer matches the one provided, the
* override is applied. When the {@link TrackGroupArray} does not match, the override has no
* effect. The override replaces any previous override for the specified {@link TrackGroupArray}
* for the specified {@link Renderer}.
*
* <p>Passing a {@code null} override will cause the renderer to be disabled when the {@link
* TrackGroupArray} mapped to it matches the one provided. When the {@link TrackGroupArray} does
* not match a {@code null} override has no effect. Hence a {@code null} override differs from
* disabling the renderer using {@link #setRendererDisabled(int, boolean)} because the renderer is
* disabled conditionally on the {@link TrackGroupArray} mapped to it, where-as {@link
* #setRendererDisabled(int, boolean)} disables the renderer unconditionally.
*
* <p>To remove overrides use {@link #clearSelectionOverride(int, TrackGroupArray)}, {@link
* #clearSelectionOverrides(int)} or {@link #clearSelectionOverrides()}.
*
* @param rendererIndex The renderer index.
* @param groups The {@link TrackGroupArray} for which the override should be applied.
* @param override The override.
* @deprecated Use {@link ParametersBuilder#setSelectionOverride(int, TrackGroupArray,
* SelectionOverride)}.
*/
@Deprecated
public final void setSelectionOverride(
int rendererIndex, TrackGroupArray groups, SelectionOverride override) {
Map<TrackGroupArray, SelectionOverride> overrides = selectionOverrides.get(rendererIndex);
if (overrides == null) {
overrides = new HashMap<>();
selectionOverrides.put(rendererIndex, overrides);
}
if (overrides.containsKey(groups) && Util.areEqual(overrides.get(groups), override)) {
// The override is unchanged.
return;
}
overrides.put(groups, override);
invalidate();
setParameters(buildUponParameters().setSelectionOverride(rendererIndex, groups, override));
}
/**
* Returns whether there is an override for the specified renderer and {@link TrackGroupArray}.
*
* @param rendererIndex The renderer index.
* @param groups The {@link TrackGroupArray}.
* @return Whether there is an override.
*/
/** @deprecated Use {@link Parameters#hasSelectionOverride(int, TrackGroupArray)}. * */
@Deprecated
public final boolean hasSelectionOverride(int rendererIndex, TrackGroupArray groups) {
Map<TrackGroupArray, SelectionOverride> overrides = selectionOverrides.get(rendererIndex);
return overrides != null && overrides.containsKey(groups);
return getParameters().hasSelectionOverride(rendererIndex, groups);
}
/**
* Returns the override for the specified renderer and {@link TrackGroupArray}.
*
* @param rendererIndex The renderer index.
* @param groups The {@link TrackGroupArray}.
* @return The override, or null if no override exists.
*/
/** @deprecated Use {@link Parameters#getSelectionOverride(int, TrackGroupArray)}. */
@Deprecated
public final SelectionOverride getSelectionOverride(int rendererIndex, TrackGroupArray groups) {
Map<TrackGroupArray, SelectionOverride> overrides = selectionOverrides.get(rendererIndex);
return overrides != null ? overrides.get(groups) : null;
return getParameters().getSelectionOverride(rendererIndex, groups);
}
/**
* Clears a track selection override for the specified renderer and {@link TrackGroupArray}.
*
* @param rendererIndex The renderer index.
* @param groups The {@link TrackGroupArray} for which the override should be cleared.
*/
/** @deprecated Use {@link ParametersBuilder#clearSelectionOverride(int, TrackGroupArray)}. */
@Deprecated
public final void clearSelectionOverride(int rendererIndex, TrackGroupArray groups) {
Map<TrackGroupArray, SelectionOverride> overrides = selectionOverrides.get(rendererIndex);
if (overrides == null || !overrides.containsKey(groups)) {
// Nothing to clear.
return;
}
overrides.remove(groups);
if (overrides.isEmpty()) {
selectionOverrides.remove(rendererIndex);
}
invalidate();
setParameters(buildUponParameters().clearSelectionOverride(rendererIndex, groups));
}
/**
* Clears all track selection overrides for the specified renderer.
*
* @param rendererIndex The renderer index.
*/
/** @deprecated Use {@link ParametersBuilder#clearSelectionOverrides(int)}. */
@Deprecated
public final void clearSelectionOverrides(int rendererIndex) {
Map<TrackGroupArray, SelectionOverride> overrides = selectionOverrides.get(rendererIndex);
if (overrides == null || overrides.isEmpty()) {
// Nothing to clear.
return;
}
selectionOverrides.remove(rendererIndex);
invalidate();
setParameters(buildUponParameters().clearSelectionOverrides(rendererIndex));
}
/** Clears all track selection overrides for all renderers. */
/** @deprecated Use {@link ParametersBuilder#clearSelectionOverrides()}. */
@Deprecated
public final void clearSelectionOverrides() {
if (selectionOverrides.size() == 0) {
// Nothing to clear.
return;
}
selectionOverrides.clear();
invalidate();
setParameters(buildUponParameters().clearSelectionOverrides());
}
/**
* Enables or disables tunneling. To enable tunneling, pass an audio session id to use when in
* tunneling mode. Session ids can be generated using {@link
* C#generateAudioSessionIdV21(Context)}. To disable tunneling pass {@link
* C#AUDIO_SESSION_ID_UNSET}. Tunneling will only be activated if it's both enabled and supported
* by the audio and video renderers for the selected tracks.
*
* @param tunnelingAudioSessionId The audio session id to use when tunneling, or {@link
* C#AUDIO_SESSION_ID_UNSET} to disable tunneling.
*/
/** @deprecated Use {@link ParametersBuilder#setTunnelingAudioSessionId(int)}. */
@Deprecated
public void setTunnelingAudioSessionId(int tunnelingAudioSessionId) {
if (this.tunnelingAudioSessionId != tunnelingAudioSessionId) {
this.tunnelingAudioSessionId = tunnelingAudioSessionId;
invalidate();
}
setParameters(buildUponParameters().setTunnelingAudioSessionId(tunnelingAudioSessionId));
}
// MappingTrackSelector implementation.
......@@ -935,29 +1165,33 @@ public class DefaultTrackSelector extends MappingTrackSelector {
int[][][] rendererFormatSupports,
int[] rendererMixedMimeTypeAdaptationSupports)
throws ExoPlaybackException {
Parameters params = parametersReference.get();
int rendererCount = mappedTrackInfo.getRendererCount();
TrackSelection[] rendererTrackSelections =
selectAllTracks(
mappedTrackInfo, rendererFormatSupports, rendererMixedMimeTypeAdaptationSupports);
mappedTrackInfo,
rendererFormatSupports,
rendererMixedMimeTypeAdaptationSupports,
params);
// Apply track disabling and overriding.
for (int i = 0; i < rendererCount; i++) {
if (rendererDisabledFlags.get(i)) {
if (params.getRendererDisabled(i)) {
rendererTrackSelections[i] = null;
} else {
TrackGroupArray rendererTrackGroup = mappedTrackInfo.getTrackGroups(i);
if (hasSelectionOverride(i, rendererTrackGroup)) {
SelectionOverride override = selectionOverrides.get(i).get(rendererTrackGroup);
TrackGroupArray rendererTrackGroups = mappedTrackInfo.getTrackGroups(i);
if (params.hasSelectionOverride(i, rendererTrackGroups)) {
SelectionOverride override = params.getSelectionOverride(i, rendererTrackGroups);
if (override == null) {
rendererTrackSelections[i] = null;
} else if (override.length == 1) {
rendererTrackSelections[i] =
new FixedTrackSelection(
rendererTrackGroup.get(override.groupIndex), override.tracks[0]);
rendererTrackGroups.get(override.groupIndex), override.tracks[0]);
} else {
rendererTrackSelections[i] =
adaptiveTrackSelectionFactory.createTrackSelection(
rendererTrackGroup.get(override.groupIndex), override.tracks);
rendererTrackGroups.get(override.groupIndex), override.tracks);
}
}
}
......@@ -967,7 +1201,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
// selections, and null otherwise.
RendererConfiguration[] rendererConfigurations = new RendererConfiguration[rendererCount];
for (int i = 0; i < rendererCount; i++) {
boolean forceRendererDisabled = rendererDisabledFlags.get(i);
boolean forceRendererDisabled = params.getRendererDisabled(i);
boolean rendererEnabled =
!forceRendererDisabled
&& (mappedTrackInfo.getRendererType(i) == C.TRACK_TYPE_NONE
......@@ -981,7 +1215,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
rendererFormatSupports,
rendererConfigurations,
rendererTrackSelections,
tunnelingAudioSessionId);
params.tunnelingAudioSessionId);
return Pair.create(rendererConfigurations, rendererTrackSelections);
}
......@@ -1007,11 +1241,11 @@ public class DefaultTrackSelector extends MappingTrackSelector {
protected TrackSelection[] selectAllTracks(
MappedTrackInfo mappedTrackInfo,
int[][][] rendererFormatSupports,
int[] rendererMixedMimeTypeAdaptationSupports)
int[] rendererMixedMimeTypeAdaptationSupports,
Parameters params)
throws ExoPlaybackException {
int rendererCount = mappedTrackInfo.getRendererCount();
TrackSelection[] rendererTrackSelections = new TrackSelection[rendererCount];
Parameters params = paramsReference.get();
boolean seenVideoRendererWithMappedTracks = false;
boolean selectedVideoTracks = false;
......@@ -1073,8 +1307,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
// Video track selection implementation.
/**
* Called by {@link #selectAllTracks(MappedTrackInfo, int[][][], int[])} to create a {@link
* TrackSelection} for a video renderer.
* Called by {@link #selectAllTracks(MappedTrackInfo, int[][][], int[], Parameters)} to create a
* {@link TrackSelection} for a video renderer.
*
* @param groups The {@link TrackGroupArray} mapped to the renderer.
* @param formatSupports The result of {@link RendererCapabilities#supportsFormat} for each mapped
......@@ -1279,8 +1513,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
// Audio track selection implementation.
/**
* Called by {@link #selectAllTracks(MappedTrackInfo, int[][][], int[])} to create a {@link
* TrackSelection} for an audio renderer.
* Called by {@link #selectAllTracks(MappedTrackInfo, int[][][], int[], Parameters)} to create a
* {@link TrackSelection} for an audio renderer.
*
* @param groups The {@link TrackGroupArray} mapped to the renderer.
* @param formatSupports The result of {@link RendererCapabilities#supportsFormat} for each mapped
......@@ -1394,8 +1628,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
// Text track selection implementation.
/**
* Called by {@link #selectAllTracks(MappedTrackInfo, int[][][], int[])} to create a {@link
* TrackSelection} for a text renderer.
* Called by {@link #selectAllTracks(MappedTrackInfo, int[][][], int[], Parameters)} to create a
* {@link TrackSelection} for a text renderer.
*
* @param groups The {@link TrackGroupArray} mapped to the renderer.
* @param formatSupport The result of {@link RendererCapabilities#supportsFormat} for each mapped
......@@ -1466,8 +1700,8 @@ public class DefaultTrackSelector extends MappingTrackSelector {
// General track selection methods.
/**
* Called by {@link #selectAllTracks(MappedTrackInfo, int[][][], int[])} to create a {@link
* TrackSelection} for a renderer whose type is neither video, audio or text.
* Called by {@link #selectAllTracks(MappedTrackInfo, int[][][], int[], Parameters)} to create a
* {@link TrackSelection} for a renderer whose type is neither video, audio or text.
*
* @param trackType The type of the renderer.
* @param groups The {@link TrackGroupArray} mapped to the renderer.
......
......@@ -25,6 +25,8 @@ import static org.mockito.Mockito.verify;
import static org.mockito.MockitoAnnotations.initMocks;
import android.os.Parcel;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.Format;
......@@ -120,8 +122,18 @@ public final class DefaultTrackSelectorTest {
/** Tests {@link Parameters} {@link android.os.Parcelable} implementation. */
@Test
public void testParametersParcelable() {
SparseArray<Map<TrackGroupArray, SelectionOverride>> selectionOverrides = new SparseArray<>();
Map<TrackGroupArray, SelectionOverride> videoOverrides = new HashMap<>();
videoOverrides.put(new TrackGroupArray(VIDEO_TRACK_GROUP), new SelectionOverride(0, 1));
selectionOverrides.put(2, videoOverrides);
SparseBooleanArray rendererDisabledFlags = new SparseBooleanArray();
rendererDisabledFlags.put(3, true);
Parameters parametersToParcel =
new Parameters(
selectionOverrides,
rendererDisabledFlags,
/* preferredAudioLanguage= */ "en",
/* preferredTextLanguage= */ "de",
/* selectUndeterminedTextLanguage= */ false,
......@@ -136,7 +148,8 @@ public final class DefaultTrackSelectorTest {
/* exceedRendererCapabilitiesIfNecessary= */ true,
/* viewportWidth= */ 4,
/* viewportHeight= */ 5,
/* viewportOrientationMayChange= */ false);
/* viewportOrientationMayChange= */ false,
/* tunnelingAudioSessionId= */ C.AUDIO_SESSION_ID_UNSET);
Parcel parcel = Parcel.obtain();
parametersToParcel.writeToParcel(parcel, 0);
......@@ -170,7 +183,10 @@ public final class DefaultTrackSelectorTest {
@Test
public void testSelectTracksWithNullOverride() throws ExoPlaybackException {
DefaultTrackSelector trackSelector = new DefaultTrackSelector();
trackSelector.setSelectionOverride(0, new TrackGroupArray(VIDEO_TRACK_GROUP), null);
trackSelector.setParameters(
trackSelector
.buildUponParameters()
.setSelectionOverride(0, new TrackGroupArray(VIDEO_TRACK_GROUP), null));
TrackSelectorResult result = trackSelector.selectTracks(RENDERER_CAPABILITIES, TRACK_GROUPS);
assertTrackSelections(result, new TrackSelection[] {null, TRACK_SELECTIONS[1]});
assertThat(result.rendererConfigurations)
......@@ -181,8 +197,11 @@ public final class DefaultTrackSelectorTest {
@Test
public void testSelectTracksWithClearedNullOverride() throws ExoPlaybackException {
DefaultTrackSelector trackSelector = new DefaultTrackSelector();
trackSelector.setSelectionOverride(0, new TrackGroupArray(VIDEO_TRACK_GROUP), null);
trackSelector.clearSelectionOverride(0, new TrackGroupArray(VIDEO_TRACK_GROUP));
trackSelector.setParameters(
trackSelector
.buildUponParameters()
.setSelectionOverride(0, new TrackGroupArray(VIDEO_TRACK_GROUP), null)
.clearSelectionOverride(0, new TrackGroupArray(VIDEO_TRACK_GROUP)));
TrackSelectorResult result = trackSelector.selectTracks(RENDERER_CAPABILITIES, TRACK_GROUPS);
assertTrackSelections(result, TRACK_SELECTIONS);
assertThat(result.rendererConfigurations)
......@@ -193,7 +212,10 @@ public final class DefaultTrackSelectorTest {
@Test
public void testSelectTracksWithNullOverrideForDifferentTracks() throws ExoPlaybackException {
DefaultTrackSelector trackSelector = new DefaultTrackSelector();
trackSelector.setSelectionOverride(0, new TrackGroupArray(VIDEO_TRACK_GROUP), null);
trackSelector.setParameters(
trackSelector
.buildUponParameters()
.setSelectionOverride(0, new TrackGroupArray(VIDEO_TRACK_GROUP), null));
TrackSelectorResult result =
trackSelector.selectTracks(
RENDERER_CAPABILITIES,
......@@ -207,7 +229,7 @@ public final class DefaultTrackSelectorTest {
@Test
public void testSelectTracksWithDisabledRenderer() throws ExoPlaybackException {
DefaultTrackSelector trackSelector = new DefaultTrackSelector();
trackSelector.setRendererDisabled(1, true);
trackSelector.setParameters(trackSelector.buildUponParameters().setRendererDisabled(1, true));
TrackSelectorResult result = trackSelector.selectTracks(RENDERER_CAPABILITIES, TRACK_GROUPS);
assertTrackSelections(result, new TrackSelection[] {TRACK_SELECTIONS[0], null});
assertThat(new RendererConfiguration[] {DEFAULT, null})
......@@ -218,8 +240,11 @@ public final class DefaultTrackSelectorTest {
@Test
public void testSelectTracksWithClearedDisabledRenderer() throws ExoPlaybackException {
DefaultTrackSelector trackSelector = new DefaultTrackSelector();
trackSelector.setRendererDisabled(1, true);
trackSelector.setRendererDisabled(1, false);
trackSelector.setParameters(
trackSelector
.buildUponParameters()
.setRendererDisabled(1, true)
.setRendererDisabled(1, false));
TrackSelectorResult result = trackSelector.selectTracks(RENDERER_CAPABILITIES, TRACK_GROUPS);
assertTrackSelections(result, TRACK_SELECTIONS);
assertThat(new RendererConfiguration[] {DEFAULT, DEFAULT})
......@@ -241,7 +266,7 @@ public final class DefaultTrackSelectorTest {
@Test
public void testSelectTracksWithDisabledNoSampleRenderer() throws ExoPlaybackException {
DefaultTrackSelector trackSelector = new DefaultTrackSelector();
trackSelector.setRendererDisabled(1, true);
trackSelector.setParameters(trackSelector.buildUponParameters().setRendererDisabled(1, true));
TrackSelectorResult result =
trackSelector.selectTracks(RENDERER_CAPABILITIES_WITH_NO_SAMPLE_RENDERER, TRACK_GROUPS);
assertTrackSelections(result, TRACK_SELECTIONS_WITH_NO_SAMPLE_RENDERER);
......
......@@ -397,7 +397,8 @@ public final class DashTestRunner {
protected TrackSelection[] selectAllTracks(
MappedTrackInfo mappedTrackInfo,
int[][][] rendererFormatSupports,
int[] rendererMixedMimeTypeAdaptationSupports)
int[] rendererMixedMimeTypeAdaptationSupports,
Parameters parameters)
throws ExoPlaybackException {
Assertions.checkState(
mappedTrackInfo.getRendererType(VIDEO_RENDERER_INDEX) == C.TRACK_TYPE_VIDEO);
......
......@@ -33,6 +33,7 @@ import com.google.android.exoplayer2.testutil.ActionSchedule.ActionNode;
import com.google.android.exoplayer2.testutil.ActionSchedule.PlayerRunnable;
import com.google.android.exoplayer2.testutil.ActionSchedule.PlayerTarget;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.Parameters;
import com.google.android.exoplayer2.util.HandlerWrapper;
/**
......@@ -219,7 +220,10 @@ public abstract class Action {
}
/** Calls {@link DefaultTrackSelector#setRendererDisabled(int, boolean)}. */
/**
* Updates the {@link Parameters} of a {@link DefaultTrackSelector} to specify whether the
* renderer at a given index should be disabled.
*/
public static final class SetRendererDisabled extends Action {
private final int rendererIndex;
......@@ -239,7 +243,8 @@ public abstract class Action {
@Override
protected void doActionImpl(
SimpleExoPlayer player, DefaultTrackSelector trackSelector, Surface surface) {
trackSelector.setRendererDisabled(rendererIndex, disabled);
trackSelector.setParameters(
trackSelector.buildUponParameters().setRendererDisabled(rendererIndex, disabled));
}
}
......
......@@ -48,7 +48,8 @@ public class FakeTrackSelector extends DefaultTrackSelector {
protected TrackSelection[] selectAllTracks(
MappedTrackInfo mappedTrackInfo,
int[][][] rendererFormatSupports,
int[] rendererMixedMimeTypeAdaptationSupports)
int[] rendererMixedMimeTypeAdaptationSupports,
Parameters params)
throws ExoPlaybackException {
TrackSelection[] selections = new TrackSelection[mappedTrackInfo.length];
for (int i = 0; i < mappedTrackInfo.length; i++) {
......
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