From 7d6b0e1fdab2708f4192cec1621fb50d384a06e1 Mon Sep 17 00:00:00 2001 From: olly Date: Mon, 23 Apr 2018 06:17:07 -0700 Subject: [PATCH] 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 --- .../exoplayer2/demo/PlayerActivity.java | 81 ++- .../exoplayer2/demo/TrackSelectionHelper.java | 15 +- .../trackselection/DefaultTrackSelector.java | 644 ++++++++++++------ .../DefaultTrackSelectorTest.java | 43 +- .../playbacktests/gts/DashTestRunner.java | 3 +- .../android/exoplayer2/testutil/Action.java | 9 +- .../testutil/FakeTrackSelector.java | 3 +- 7 files changed, 552 insertions(+), 246 deletions(-) diff --git a/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java b/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java index 03d816af75..2a0a3ceb6c 100644 --- a/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java +++ b/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java @@ -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 clearResumePosition() { - resumeWindow = C.INDEX_UNSET; - resumePosition = C.TIME_UNSET; + private void updateStartPosition() { + if (player != null) { + startAutoPlay = player.getPlayWhenReady(); + startWindow = player.getCurrentWindowIndex(); + startPosition = Math.max(0, player.getContentPosition()); + } + } + + 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(); } diff --git a/demos/main/src/main/java/com/google/android/exoplayer2/demo/TrackSelectionHelper.java b/demos/main/src/main/java/com/google/android/exoplayer2/demo/TrackSelectionHelper.java index d70e554473..66bef48500 100644 --- a/demos/main/src/main/java/com/google/android/exoplayer2/demo/TrackSelectionHelper.java +++ b/demos/main/src/main/java/com/google/android/exoplayer2/demo/TrackSelectionHelper.java @@ -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 diff --git a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java index 6c5e3dace5..9f7985b22b 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelector.java @@ -45,24 +45,91 @@ 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)}. + * + *

Modifying parameters

+ * + * 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: + * + *
{@code
+ * // Build on the current parameters.
+ * Parameters currentParameters = trackSelector.getParameters();
+ * // Build the resulting parameters.
+ * Parameters newParameters = currentParameters
+ *     .buildUpon()
+ *     .setMaxVideoSizeSd()
+ *     .setPreferredAudioLanguage("deu")
+ *     .build();
+ * // Set the new parameters.
+ * trackSelector.setParameters(newParameters);
+ * }
+ * + * Convenience methods and chaining allow this to be written more concisely as: + * + *
{@code
+ * trackSelector.setParameters(
+ *     trackSelector
+ *         .buildUponParameters()
+ *         .setMaxVideoSizeSd()
+ *         .setPreferredAudioLanguage("deu"));
+ * }
+ * + * Selection {@link Parameters} support many different options, some of which are described below. + * + *

Track selection overrides

+ * + * 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: + * + *
{@code
+ * MappedTrackInfo mappedTrackInfo = trackSelector.getCurrentMappedTrackInfo();
+ * TrackGroupArray rendererTrackGroups = mappedTrackInfo == null ? null
+ *     : mappedTrackInfo.getTrackGroups(rendererIndex);
+ * }
+ * + * If {@code rendererTrackGroups} is null then there aren't any currently mapped tracks, and so + * 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} and the {@code + * trackIndices} within the group it that should be selected. The override can then be specified + * using {@link ParametersBuilder#setSelectionOverride}: + * + *
{@code
+ * SelectionOverride selectionOverride = new SelectionOverride(groupIndex, trackIndices);
+ * trackSelector.setParameters(
+ *     trackSelector
+ *         .buildUponParameters()
+ *         .setSelectionOverride(rendererIndex, rendererTrackGroups, selectionOverride));
+ * }
+ * + *

Disabling renderers

+ * + * 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. * *

Constraint based track selection

* - * 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: + * 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: * *
{@code
- * Parameters currentParameters = trackSelector.getParameters();
- * // Generate new parameters to prefer German audio and impose a maximum video size constraint.
- * Parameters newParameters = currentParameters
- *     .withPreferredAudioLanguage("deu")
- *     .withMaxVideoSize(1024, 768);
- * // Set the new parameters on the selector.
- * trackSelector.setParameters(newParameters);
+ * trackSelector.setParameters(
+ *     trackSelector
+ *         .buildUponParameters()
+ *         .setMaxVideoSizeSd()
+ *         .setPreferredAudioLanguage("deu"));
  * }
* * There are several benefits to using constraint based track selection instead of specific track @@ -77,46 +144,11 @@ import java.util.concurrent.atomic.AtomicReference; * only applied to periods whose tracks match those for which the override was set. * * - *

Track overrides

- * - * 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: - * - *
{@code
- * MappedTrackInfo mappedTrackInfo = trackSelector.getCurrentMappedTrackInfo();
- * TrackGroupArray rendererTrackGroups = mappedTrackInfo == null ? null
- *     : mappedTrackInfo.getTrackGroups(rendererIndex);
- * }
- * - * If {@code rendererTrackGroups} is null then there aren't any currently mapped tracks, and so - * 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: - * - *
{@code
- * trackSelector.setSelectionOverride(rendererIndex, rendererTrackGroups,
- *     new SelectionOverride(groupIndex, trackIndices));
- * }
- * - * If the override is {@code null} then no tracks will be selected. - * - *

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

Disabling renderers

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

Tunneling

* * 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> 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; } /** @@ -342,11 +381,134 @@ public class DefaultTrackSelector extends MappingTrackSelector { return this; } + /** + * 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. + * + *

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}. + * + *

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. + * + *

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 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 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 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> 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>(), + 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> 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 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 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 CREATOR = @@ -628,6 +854,93 @@ public class DefaultTrackSelector extends MappingTrackSelector { return new Parameters[size]; } }; + + // Static utility methods. + + private static SparseArray> readSelectionOverrides( + Parcel in) { + int renderersWithOverridesCount = in.readInt(); + SparseArray> selectionOverrides = + new SparseArray<>(renderersWithOverridesCount); + for (int i = 0; i < renderersWithOverridesCount; i++) { + int rendererIndex = in.readInt(); + int overrideCount = in.readInt(); + Map 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> selectionOverrides) { + int renderersWithOverridesCount = selectionOverrides.size(); + dest.writeInt(renderersWithOverridesCount); + for (int i = 0; i < renderersWithOverridesCount; i++) { + int rendererIndex = selectionOverrides.keyAt(i); + Map overrides = selectionOverrides.valueAt(i); + int overrideCount = overrides.size(); + dest.writeInt(rendererIndex); + dest.writeInt(overrideCount); + for (Map.Entry 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> first, + SparseArray> 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 first, + Map second) { + int firstSize = first.size(); + if (second.size() != firstSize) { + return false; + } + for (Map.Entry 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 paramsReference; - private final SparseArray> selectionOverrides; - private final SparseBooleanArray rendererDisabledFlags; - - private int tunnelingAudioSessionId; + private final AtomicReference 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(); } } + /** + * Atomically sets the provided parameters for track selection. + * + * @param parametersBuilder A builder from which to obtain the parameters for track selection. + */ + public void setParameters(ParametersBuilder parametersBuilder) { + setParameters(parametersBuilder.build()); + } + /** * Gets the current selection parameters. * * @return The current selection parameters. */ public Parameters getParameters() { - return paramsReference.get(); + return parametersReference.get(); } - /** - * 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. - */ + /** 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. - * - *

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}. - * - *

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

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 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 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 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 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 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. diff --git a/library/core/src/test/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelectorTest.java b/library/core/src/test/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelectorTest.java index a97b9fc567..2ba63d6773 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelectorTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/trackselection/DefaultTrackSelectorTest.java @@ -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> selectionOverrides = new SparseArray<>(); + Map 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); diff --git a/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashTestRunner.java b/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashTestRunner.java index 28a386730b..e9d8acb031 100644 --- a/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashTestRunner.java +++ b/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashTestRunner.java @@ -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); diff --git a/testutils/src/main/java/com/google/android/exoplayer2/testutil/Action.java b/testutils/src/main/java/com/google/android/exoplayer2/testutil/Action.java index d969d799f6..a6c3438a52 100644 --- a/testutils/src/main/java/com/google/android/exoplayer2/testutil/Action.java +++ b/testutils/src/main/java/com/google/android/exoplayer2/testutil/Action.java @@ -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)); } } diff --git a/testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/FakeTrackSelector.java b/testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/FakeTrackSelector.java index 7cc0309742..4d4a53bcdd 100644 --- a/testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/FakeTrackSelector.java +++ b/testutils_robolectric/src/main/java/com/google/android/exoplayer2/testutil/FakeTrackSelector.java @@ -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++) {