diff --git a/library/common/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelectionOverrides.java b/library/common/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelectionOverrides.java
new file mode 100644
index 0000000000..65c659cce8
--- /dev/null
+++ b/library/common/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelectionOverrides.java
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.android.exoplayer2.trackselection;
+
+import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
+import static com.google.android.exoplayer2.util.BundleableUtil.fromBundleNullableList;
+import static com.google.android.exoplayer2.util.BundleableUtil.toBundleArrayList;
+import static java.util.Collections.max;
+import static java.util.Collections.min;
+
+import android.os.Bundle;
+import androidx.annotation.IntDef;
+import androidx.annotation.Nullable;
+import com.google.android.exoplayer2.trackselection.C.TrackType;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.primitives.Ints;
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Forces the selection of the specified tracks in {@link TrackGroup TrackGroups}.
+ *
+ *
Each {@link TrackSelectionOverride override} only affects the selection of tracks of that
+ * {@link TrackType type}. For example overriding the selection of an {@link C#TRACK_TYPE_AUDIO
+ * audio} {@link TrackGroup} will not affect the selection of {@link C#TRACK_TYPE_VIDEO video} or
+ * {@link C#TRACK_TYPE_TEXT text} tracks.
+ *
+ *
If multiple {@link TrackGroup TrackGroups} of the same {@link TrackType} are overridden, which
+ * tracks will be selected depend on the player capabilities. For example, by default {@code
+ * ExoPlayer} doesn't support selecting more than one {@link TrackGroup} per {@link TrackType}.
+ *
+ *
Overrides of {@link TrackGroup} that are not currently available are ignored. For example,
+ * when the player transitions to the next {@link MediaItem} in a playlist, any overrides of the
+ * previous {@link MediaItem} are ignored.
+ *
+ * @see TrackSelectionParameters#trackSelectionOverrides
+ */
+public final class TrackSelectionOverrides implements Bundleable {
+
+ /** Builder for {@link TrackSelectionOverrides}. */
+ public static final class Builder {
+ // Cannot use ImmutableMap.Builder as it doesn't support removing entries.
+ private final HashMap overrides;
+
+ /** Creates an builder with no {@link TrackSelectionOverride}. */
+ public Builder() {
+ overrides = new HashMap<>();
+ }
+
+ private Builder(Map overrides) {
+ this.overrides = new HashMap<>(overrides);
+ }
+
+ /** Adds an override for the provided {@link TrackGroup}. */
+ public Builder addOverride(TrackSelectionOverride override) {
+ overrides.put(override.trackGroup, override);
+ return this;
+ }
+
+ /** Removes the override associated with the provided {@link TrackGroup} if present. */
+ public Builder clearOverride(TrackGroup trackGroup) {
+ overrides.remove(trackGroup);
+ return this;
+ }
+
+ /** Set the override for the type of the provided {@link TrackGroup}. */
+ public Builder setOverrideForType(TrackSelectionOverride override) {
+ clearOverridesOfType(override.getTrackType());
+ overrides.put(override.trackGroup, override);
+ return this;
+ }
+
+ /**
+ * Remove any override associated with {@link TrackGroup TrackGroups} of type {@code trackType}.
+ */
+ public Builder clearOverridesOfType(@TrackType int trackType) {
+ for (Iterator it = overrides.values().iterator(); it.hasNext(); ) {
+ TrackSelectionOverride trackSelectionOverride = it.next();
+ if (trackSelectionOverride.getTrackType() == trackType) {
+ it.remove();
+ }
+ }
+ return this;
+ }
+
+ /** Returns a new {@link TrackSelectionOverrides} instance with the current builder values. */
+ public TrackSelectionOverrides build() {
+ return new TrackSelectionOverrides(overrides);
+ }
+ }
+
+ /**
+ * Forces the selection of {@link #trackIndexes} for a {@link TrackGroup}.
+ *
+ * If multiple {link #tracks} are overridden, as many as possible will be selected depending on
+ * the player capabilities.
+ *
+ *
If a {@link TrackSelectionOverride} has no tracks ({@code tracks.isEmpty()}), no tracks will
+ * be played. This is similar to {@link TrackSelectionParameters#disabledTrackTypes}, except it
+ * will only affect the playback of the associated {@link TrackGroup}. For example, if the only
+ * {@link C#TRACK_TYPE_VIDEO} {@link TrackGroup} is associated with no tracks, no video will play
+ * until the next video starts.
+ */
+ public static final class TrackSelectionOverride implements Bundleable {
+
+ /** The {@link TrackGroup} whose {@link #trackIndexes} are forced to be selected. */
+ public final TrackGroup trackGroup;
+ /** The index of tracks in a {@link TrackGroup} to be selected. */
+ public final ImmutableList trackIndexes;
+
+ /** Constructs an instance to force all tracks in {@code trackGroup} to be selected. */
+ public TrackSelectionOverride(TrackGroup trackGroup) {
+ this.trackGroup = trackGroup;
+ ImmutableList.Builder builder = new ImmutableList.Builder<>();
+ for (int i = 0; i < trackGroup.length; i++) {
+ builder.add(i);
+ }
+ this.trackIndexes = builder.build();
+ }
+
+ /**
+ * Constructs an instance to force {@code trackIndexes} in {@code trackGroup} to be selected.
+ *
+ * @param trackGroup The {@link TrackGroup} for which to override the track selection.
+ * @param trackIndexes The indexes of the tracks in the {@link TrackGroup} to select.
+ */
+ public TrackSelectionOverride(TrackGroup trackGroup, List trackIndexes) {
+ if (!trackIndexes.isEmpty()) {
+ if (min(trackIndexes) < 0 || max(trackIndexes) >= trackGroup.length) {
+ throw new IndexOutOfBoundsException();
+ }
+ }
+ this.trackGroup = trackGroup;
+ this.trackIndexes = ImmutableList.copyOf(trackIndexes);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ TrackSelectionOverride that = (TrackSelectionOverride) obj;
+ return trackGroup.equals(that.trackGroup) && trackIndexes.equals(that.trackIndexes);
+ }
+
+ @Override
+ public int hashCode() {
+ return trackGroup.hashCode() + 31 * trackIndexes.hashCode();
+ }
+
+ private @TrackType int getTrackType() {
+ return MimeTypes.getTrackType(trackGroup.getFormat(0).sampleMimeType);
+ }
+
+ // Bundleable implementation
+
+ @Documented
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ FIELD_TRACK_GROUP,
+ FIELD_TRACKS,
+ })
+ private @interface FieldNumber {}
+
+ private static final int FIELD_TRACK_GROUP = 0;
+ private static final int FIELD_TRACKS = 1;
+
+ @Override
+ public Bundle toBundle() {
+ Bundle bundle = new Bundle();
+ bundle.putBundle(keyForField(FIELD_TRACK_GROUP), trackGroup.toBundle());
+ bundle.putIntArray(keyForField(FIELD_TRACKS), Ints.toArray(trackIndexes));
+ return bundle;
+ }
+
+ /** Object that can restore {@code TrackSelectionOverride} from a {@link Bundle}. */
+ public static final Creator CREATOR =
+ bundle -> {
+ @Nullable Bundle trackGroupBundle = bundle.getBundle(keyForField(FIELD_TRACK_GROUP));
+ checkNotNull(trackGroupBundle); // Mandatory as there are no reasonable defaults.
+ TrackGroup trackGroup = TrackGroup.CREATOR.fromBundle(trackGroupBundle);
+ @Nullable int[] tracks = bundle.getIntArray(keyForField(FIELD_TRACKS));
+ if (tracks == null) {
+ return new TrackSelectionOverride(trackGroup);
+ }
+ return new TrackSelectionOverride(trackGroup, Ints.asList(tracks));
+ };
+
+ private static String keyForField(@FieldNumber int field) {
+ return Integer.toString(field, Character.MAX_RADIX);
+ }
+ }
+
+ /** Empty {@code TrackSelectionOverrides}, where no track selection is overridden. */
+ public static final TrackSelectionOverrides EMPTY =
+ new TrackSelectionOverrides(ImmutableMap.of());
+
+ private final ImmutableMap overrides;
+
+ private TrackSelectionOverrides(Map overrides) {
+ this.overrides = ImmutableMap.copyOf(overrides);
+ }
+
+ /** Returns a {@link Builder} initialized with the values of this instance. */
+ public Builder buildUpon() {
+ return new Builder(overrides);
+ }
+
+ /** Returns all {@link TrackSelectionOverride} contained. */
+ public ImmutableList asList() {
+ return ImmutableList.copyOf(overrides.values());
+ }
+
+ /**
+ * Returns the {@link TrackSelectionOverride} of the provided {@link TrackGroup} or {@code null}
+ * if there is none.
+ */
+ @Nullable
+ public TrackSelectionOverride getOverride(TrackGroup trackGroup) {
+ return overrides.get(trackGroup);
+ }
+
+ @Override
+ public boolean equals(@Nullable Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ TrackSelectionOverrides that = (TrackSelectionOverrides) obj;
+ return overrides.equals(that.overrides);
+ }
+
+ @Override
+ public int hashCode() {
+ return overrides.hashCode();
+ }
+
+ // Bundleable implementation
+
+ @Documented
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ FIELD_OVERRIDES,
+ })
+ private @interface FieldNumber {}
+
+ private static final int FIELD_OVERRIDES = 0;
+
+ @Override
+ public Bundle toBundle() {
+ Bundle bundle = new Bundle();
+ bundle.putParcelableArrayList(
+ keyForField(FIELD_OVERRIDES), toBundleArrayList(overrides.values()));
+ return bundle;
+ }
+
+ /** Object that can restore {@code TrackSelectionOverrides} from a {@link Bundle}. */
+ public static final Creator CREATOR =
+ bundle -> {
+ List trackSelectionOverrides =
+ fromBundleNullableList(
+ TrackSelectionOverride.CREATOR,
+ bundle.getParcelableArrayList(keyForField(FIELD_OVERRIDES)),
+ ImmutableList.of());
+ ImmutableMap.Builder builder =
+ new ImmutableMap.Builder<>();
+ for (int i = 0; i < trackSelectionOverrides.size(); i++) {
+ TrackSelectionOverride trackSelectionOverride = trackSelectionOverrides.get(i);
+ builder.put(trackSelectionOverride.trackGroup, trackSelectionOverride);
+ }
+ return new TrackSelectionOverrides(builder.build());
+ };
+
+ private static String keyForField(@FieldNumber int field) {
+ return Integer.toString(field, Character.MAX_RADIX);
+ }
+}
diff --git a/library/common/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelectionParameters.java b/library/common/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelectionParameters.java
index 57cdc3a970..738cf74e2b 100644
--- a/library/common/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelectionParameters.java
+++ b/library/common/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelectionParameters.java
@@ -16,8 +16,7 @@
package com.google.android.exoplayer2.trackselection;
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
-import static com.google.android.exoplayer2.util.BundleableUtil.fromBundleNullableList;
-import static com.google.android.exoplayer2.util.BundleableUtil.toBundleArrayList;
+import static com.google.android.exoplayer2.util.BundleableUtil.fromNullableBundle;
import static com.google.common.base.MoreObjects.firstNonNull;
import android.content.Context;
@@ -30,23 +29,17 @@ import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import com.google.android.exoplayer2.Bundleable;
import com.google.android.exoplayer2.C;
-import com.google.android.exoplayer2.MediaItem;
-import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.util.Util;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.primitives.Ints;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.util.List;
import java.util.Locale;
-import java.util.Map;
import java.util.Set;
import org.checkerframework.checker.initialization.qual.UnknownInitialization;
import org.checkerframework.checker.nullness.qual.EnsuresNonNull;
-import org.checkerframework.checker.nullness.qual.NonNull;
/**
* Constraint parameters for track selection.
@@ -100,7 +93,7 @@ public class TrackSelectionParameters implements Bundleable {
// General
private boolean forceLowestBitrate;
private boolean forceHighestSupportedBitrate;
- private ImmutableMap trackSelectionOverrides;
+ private TrackSelectionOverrides trackSelectionOverrides;
private ImmutableSet<@C.TrackType Integer> disabledTrackTypes;
/**
@@ -131,7 +124,7 @@ public class TrackSelectionParameters implements Bundleable {
// General
forceLowestBitrate = false;
forceHighestSupportedBitrate = false;
- trackSelectionOverrides = ImmutableMap.of();
+ trackSelectionOverrides = TrackSelectionOverrides.EMPTY;
disabledTrackTypes = ImmutableSet.of();
}
@@ -233,17 +226,11 @@ public class TrackSelectionParameters implements Bundleable {
bundle.getBoolean(
keyForField(FIELD_FORCE_HIGHEST_SUPPORTED_BITRATE),
DEFAULT_WITHOUT_CONTEXT.forceHighestSupportedBitrate);
- List keys =
- fromBundleNullableList(
- TrackGroup.CREATOR,
- bundle.getParcelableArrayList(keyForField(FIELD_SELECTION_OVERRIDE_KEYS)),
- ImmutableList.of());
- List values =
- fromBundleNullableList(
- TrackSelectionOverride.CREATOR,
- bundle.getParcelableArrayList(keyForField(FIELD_SELECTION_OVERRIDE_VALUES)),
- ImmutableList.of());
- trackSelectionOverrides = zipToMap(keys, values);
+ trackSelectionOverrides =
+ fromNullableBundle(
+ TrackSelectionOverrides.CREATOR,
+ bundle.getBundle(keyForField(FIELD_SELECTION_OVERRIDE_KEYS)),
+ TrackSelectionOverrides.EMPTY);
disabledTrackTypes =
ImmutableSet.copyOf(
Ints.asList(
@@ -642,9 +629,8 @@ public class TrackSelectionParameters implements Bundleable {
* @param trackSelectionOverrides The track selection overrides.
* @return This builder.
*/
- public Builder setTrackSelectionOverrides(
- Map trackSelectionOverrides) {
- this.trackSelectionOverrides = ImmutableMap.copyOf(trackSelectionOverrides);
+ public Builder setTrackSelectionOverrides(TrackSelectionOverrides trackSelectionOverrides) {
+ this.trackSelectionOverrides = trackSelectionOverrides;
return this;
}
@@ -692,83 +678,6 @@ public class TrackSelectionParameters implements Bundleable {
}
return listBuilder.build();
}
-
- private static ImmutableMap<@NonNull K, @NonNull V> zipToMap(
- List<@NonNull K> keys, List<@NonNull V> values) {
- ImmutableMap.Builder<@NonNull K, @NonNull V> builder = new ImmutableMap.Builder<>();
- for (int i = 0; i < keys.size(); i++) {
- builder.put(keys.get(i), values.get(i));
- }
- return builder.build();
- }
- }
-
- /**
- * Forces the selection of {@link #tracks} for a {@link TrackGroup}.
- *
- * @see #trackSelectionOverrides
- */
- public static final class TrackSelectionOverride implements Bundleable {
- /** Force the selection of the associated {@link TrackGroup}, but no track will be played. */
- public static final TrackSelectionOverride DISABLE =
- new TrackSelectionOverride(ImmutableSet.of());
-
- /** The index of tracks in a {@link TrackGroup} to be selected. */
- public final ImmutableSet tracks;
-
- /** Constructs an instance to force {@code tracks} to be selected. */
- public TrackSelectionOverride(ImmutableSet tracks) {
- this.tracks = tracks;
- }
-
- @Override
- public boolean equals(@Nullable Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null || getClass() != obj.getClass()) {
- return false;
- }
- TrackSelectionOverride that = (TrackSelectionOverride) obj;
- return tracks.equals(that.tracks);
- }
-
- @Override
- public int hashCode() {
- return tracks.hashCode();
- }
-
- // Bundleable implementation
-
- @Documented
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({
- FIELD_TRACKS,
- })
- private @interface FieldNumber {}
-
- private static final int FIELD_TRACKS = 0;
-
- @Override
- public Bundle toBundle() {
- Bundle bundle = new Bundle();
- bundle.putIntArray(keyForField(FIELD_TRACKS), Ints.toArray(tracks));
- return bundle;
- }
-
- /** Object that can restore {@code TrackSelectionOverride} from a {@link Bundle}. */
- public static final Creator CREATOR =
- bundle -> {
- @Nullable int[] tracks = bundle.getIntArray(keyForField(FIELD_TRACKS));
- if (tracks == null) {
- return DISABLE;
- }
- return new TrackSelectionOverride(ImmutableSet.copyOf(Ints.asList(tracks)));
- };
-
- private static String keyForField(@FieldNumber int field) {
- return Integer.toString(field, Character.MAX_RADIX);
- }
}
/**
@@ -921,29 +830,8 @@ public class TrackSelectionParameters implements Bundleable {
*/
public final boolean forceHighestSupportedBitrate;
- /**
- * For each {@link TrackGroup} in the map, forces the tracks associated with it to be selected for
- * playback.
- *
- * For example if {@code trackSelectionOverrides.equals(ImmutableMap.of(trackGroup,
- * ImmutableSet.of(1, 2, 3)))}, the tracks 1, 2 and 3 of {@code trackGroup} will be selected.
- *
- *
If multiple of the current {@link TrackGroup}s of the same {@link C.TrackType} are
- * overridden, it is undetermined which one(s) will be selected. For example if a {@link
- * MediaItem} has 2 video track groups (for example 2 different angles), and both are overriden,
- * it is undetermined which one will be selected.
- *
- *
If multiple tracks of the {@link TrackGroup} are overriden, all supported (see {@link
- * C.FormatSupport}) will be selected.
- *
- *
If a {@link TrackGroup} is associated with an empty set of tracks, no tracks will be played.
- * This is similar to {@link #disabledTrackTypes}, except it will only affect the playback of the
- * associated {@link TrackGroup}. For example, if the {@link C#TRACK_TYPE_VIDEO} {@link
- * TrackGroup} is associated with no tracks, no video will play until the next video starts.
- *
- *
The default value is that no {@link TrackGroup} selections are overridden (empty map).
- */
- public final ImmutableMap trackSelectionOverrides;
+ /** Overrides to force tracks to be selected. */
+ public final TrackSelectionOverrides trackSelectionOverrides;
/**
* The track types that are disabled. No track of a disabled type will be selected, thus no track
* type contained in the set will be played. The default value is that no track type is disabled
@@ -1159,12 +1047,8 @@ public class TrackSelectionParameters implements Bundleable {
bundle.putBoolean(keyForField(FIELD_FORCE_LOWEST_BITRATE), forceLowestBitrate);
bundle.putBoolean(
keyForField(FIELD_FORCE_HIGHEST_SUPPORTED_BITRATE), forceHighestSupportedBitrate);
- bundle.putParcelableArrayList(
- keyForField(FIELD_SELECTION_OVERRIDE_KEYS),
- toBundleArrayList(trackSelectionOverrides.keySet()));
- bundle.putParcelableArrayList(
- keyForField(FIELD_SELECTION_OVERRIDE_VALUES),
- toBundleArrayList(trackSelectionOverrides.values()));
+ bundle.putBundle(
+ keyForField(FIELD_SELECTION_OVERRIDE_KEYS), trackSelectionOverrides.toBundle());
bundle.putIntArray(keyForField(FIELD_DISABLED_TRACK_TYPE), Ints.toArray(disabledTrackTypes));
return bundle;
diff --git a/library/common/src/test/java/com/google/android/exoplayer2/trackselection/TrackSelectionOverridesTest.java b/library/common/src/test/java/com/google/android/exoplayer2/trackselection/TrackSelectionOverridesTest.java
new file mode 100644
index 0000000000..2d2a27134b
--- /dev/null
+++ b/library/common/src/test/java/com/google/android/exoplayer2/trackselection/TrackSelectionOverridesTest.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.android.exoplayer2.trackselection;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.junit.Assert.assertThrows;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import com.google.android.exoplayer2.trackselection.TrackSelectionOverrides.TrackSelectionOverride;
+import com.google.common.collect.ImmutableList;
+import java.util.Arrays;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+// packages.bara.sky: import com.google.android.exoplayer2.util.MimeTypes;
+// packages.bara.sky: import com.google.android.exoplayer2.Bundleable;
+// packages.bara.sky: import com.google.android.exoplayer2.C;
+// packages.bara.sky: import com.google.android.exoplayer2.Format;
+
+/** Unit tests for {@link TrackSelectionOverrides}. */
+@RunWith(AndroidJUnit4.class)
+public final class TrackSelectionOverridesTest {
+
+ public static final TrackGroup AAC_TRACK_GROUP =
+ new TrackGroup(new Format.Builder().setSampleMimeType(MimeTypes.AUDIO_AAC).build());
+
+ private static TrackGroup newTrackGroupWithIds(int... ids) {
+ return new TrackGroup(
+ Arrays.stream(ids)
+ .mapToObj(id -> new Format.Builder().setId(id).build())
+ .toArray(Format[]::new));
+ }
+
+ @Test
+ public void newTrackSelectionOverride_withJustTrackGroup_selectsAllTracks() {
+ TrackSelectionOverride trackSelectionOverride =
+ new TrackSelectionOverride(newTrackGroupWithIds(1, 2));
+
+ assertThat(trackSelectionOverride.trackGroup).isEqualTo(newTrackGroupWithIds(1, 2));
+ assertThat(trackSelectionOverride.trackIndexes).containsExactly(0, 1).inOrder();
+ }
+
+ @Test
+ public void newTrackSelectionOverride_withTracks_selectsOnlySpecifiedTracks() {
+ TrackSelectionOverride trackSelectionOverride =
+ new TrackSelectionOverride(newTrackGroupWithIds(1, 2), ImmutableList.of(1));
+
+ assertThat(trackSelectionOverride.trackGroup).isEqualTo(newTrackGroupWithIds(1, 2));
+ assertThat(trackSelectionOverride.trackIndexes).containsExactly(1);
+ }
+
+ @Test
+ public void newTrackSelectionOverride_with0Tracks_selectsAllSpecifiedTracks() {
+ TrackSelectionOverride trackSelectionOverride =
+ new TrackSelectionOverride(newTrackGroupWithIds(1, 2), ImmutableList.of());
+
+ assertThat(trackSelectionOverride.trackGroup).isEqualTo(newTrackGroupWithIds(1, 2));
+ assertThat(trackSelectionOverride.trackIndexes).isEmpty();
+ }
+
+ @Test
+ public void newTrackSelectionOverride_withInvalidIndex_throws() {
+ assertThrows(
+ IndexOutOfBoundsException.class,
+ () -> new TrackSelectionOverride(newTrackGroupWithIds(1, 2), ImmutableList.of(2)));
+ }
+
+ @Test
+ public void roundTripViaBundle_withOverrides_yieldsEqualInstance() {
+ TrackSelectionOverrides trackSelectionOverrides =
+ new TrackSelectionOverrides.Builder()
+ .setOverrideForType(
+ new TrackSelectionOverride(newTrackGroupWithIds(3, 4), ImmutableList.of(1)))
+ .addOverride(new TrackSelectionOverride(newTrackGroupWithIds(5, 6)))
+ .build();
+
+ TrackSelectionOverrides fromBundle =
+ TrackSelectionOverrides.CREATOR.fromBundle(trackSelectionOverrides.toBundle());
+
+ assertThat(fromBundle).isEqualTo(trackSelectionOverrides);
+ assertThat(fromBundle.asList()).isEqualTo(trackSelectionOverrides.asList());
+ }
+
+ @Test
+ public void builder_byDefault_isEmpty() {
+ TrackSelectionOverrides trackSelectionOverrides = new TrackSelectionOverrides.Builder().build();
+
+ assertThat(trackSelectionOverrides.asList()).isEmpty();
+ assertThat(trackSelectionOverrides).isEqualTo(TrackSelectionOverrides.EMPTY);
+ }
+
+ @Test
+ public void addOverride_onDifferentGroups_addsOverride() {
+ TrackSelectionOverride override1 = new TrackSelectionOverride(newTrackGroupWithIds(1));
+ TrackSelectionOverride override2 = new TrackSelectionOverride(newTrackGroupWithIds(2));
+
+ TrackSelectionOverrides trackSelectionOverrides =
+ new TrackSelectionOverrides.Builder().addOverride(override1).addOverride(override2).build();
+
+ assertThat(trackSelectionOverrides.asList()).containsExactly(override1, override2);
+ assertThat(trackSelectionOverrides.getOverride(override1.trackGroup)).isEqualTo(override1);
+ assertThat(trackSelectionOverrides.getOverride(override2.trackGroup)).isEqualTo(override2);
+ }
+
+ @Test
+ public void addOverride_onSameGroup_replacesOverride() {
+ TrackGroup trackGroup = newTrackGroupWithIds(1, 2, 3);
+ TrackSelectionOverride override1 =
+ new TrackSelectionOverride(trackGroup, /* trackIndexes= */ ImmutableList.of(0));
+ TrackSelectionOverride override2 =
+ new TrackSelectionOverride(trackGroup, /* trackIndexes= */ ImmutableList.of(1));
+
+ TrackSelectionOverrides trackSelectionOverrides =
+ new TrackSelectionOverrides.Builder().addOverride(override1).addOverride(override2).build();
+
+ assertThat(trackSelectionOverrides.asList()).containsExactly(override2);
+ assertThat(trackSelectionOverrides.getOverride(override2.trackGroup)).isEqualTo(override2);
+ }
+
+ @Test
+ public void setOverrideForType_onSameType_replacesOverride() {
+ TrackSelectionOverride override1 = new TrackSelectionOverride(newTrackGroupWithIds(1));
+ TrackSelectionOverride override2 = new TrackSelectionOverride(newTrackGroupWithIds(2));
+
+ TrackSelectionOverrides trackSelectionOverrides =
+ new TrackSelectionOverrides.Builder()
+ .setOverrideForType(override1)
+ .setOverrideForType(override2)
+ .build();
+
+ assertThat(trackSelectionOverrides.asList()).containsExactly(override2);
+ assertThat(trackSelectionOverrides.getOverride(override2.trackGroup)).isEqualTo(override2);
+ }
+
+ @Test
+ public void clearOverridesOfType_ofTypeAudio_removesAudioOverride() {
+ TrackSelectionOverride override1 = new TrackSelectionOverride(AAC_TRACK_GROUP);
+ TrackSelectionOverride override2 = new TrackSelectionOverride(newTrackGroupWithIds(1));
+ TrackSelectionOverrides trackSelectionOverrides =
+ new TrackSelectionOverrides.Builder()
+ .addOverride(override1)
+ .addOverride(override2)
+ .clearOverridesOfType(C.TRACK_TYPE_AUDIO)
+ .build();
+
+ assertThat(trackSelectionOverrides.asList()).containsExactly(override2);
+ assertThat(trackSelectionOverrides.getOverride(override2.trackGroup)).isEqualTo(override2);
+ }
+
+ @Test
+ public void clearOverride_ofTypeGroup_removesOverride() {
+ TrackSelectionOverride override1 = new TrackSelectionOverride(AAC_TRACK_GROUP);
+ TrackSelectionOverride override2 = new TrackSelectionOverride(newTrackGroupWithIds(1));
+ TrackSelectionOverrides trackSelectionOverrides =
+ new TrackSelectionOverrides.Builder()
+ .addOverride(override1)
+ .addOverride(override2)
+ .clearOverride(override2.trackGroup)
+ .build();
+
+ assertThat(trackSelectionOverrides.asList()).containsExactly(override1);
+ assertThat(trackSelectionOverrides.getOverride(override1.trackGroup)).isEqualTo(override1);
+ }
+}
diff --git a/library/common/src/test/java/com/google/android/exoplayer2/trackselection/TrackSelectionParametersTest.java b/library/common/src/test/java/com/google/android/exoplayer2/trackselection/TrackSelectionParametersTest.java
index 701d88d0e6..075898d4d0 100644
--- a/library/common/src/test/java/com/google/android/exoplayer2/trackselection/TrackSelectionParametersTest.java
+++ b/library/common/src/test/java/com/google/android/exoplayer2/trackselection/TrackSelectionParametersTest.java
@@ -23,16 +23,16 @@ import com.google.android.exoplayer2.Bundleable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.SelectionOverride;
-import com.google.android.exoplayer2.trackselection.TrackSelectionParameters.TrackSelectionOverride;
+import com.google.android.exoplayer2.trackselection.TrackSelectionOverrides.TrackSelectionOverride;
import com.google.android.exoplayer2.util.MimeTypes;
-import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import org.junit.Test;
import org.junit.runner.RunWith;
/** Tests for {@link TrackSelectionParameters}. */
@RunWith(AndroidJUnit4.class)
-public class TrackSelectionParametersTest {
+public final class TrackSelectionParametersTest {
@Test
public void defaultValue_withoutChange_isAsExpected() {
@@ -64,16 +64,22 @@ public class TrackSelectionParametersTest {
// General
assertThat(parameters.forceLowestBitrate).isFalse();
assertThat(parameters.forceHighestSupportedBitrate).isFalse();
- assertThat(parameters.trackSelectionOverrides).isEmpty();
+ assertThat(parameters.trackSelectionOverrides.asList()).isEmpty();
assertThat(parameters.disabledTrackTypes).isEmpty();
}
@Test
public void parametersSet_fromDefault_isAsExpected() {
- ImmutableMap trackSelectionOverrides =
- ImmutableMap.of(
- new TrackGroup(new Format.Builder().build()),
- new TrackSelectionOverride(/* tracks= */ ImmutableSet.of(2, 3)));
+ TrackSelectionOverrides trackSelectionOverrides =
+ new TrackSelectionOverrides.Builder()
+ .addOverride(new TrackSelectionOverride(new TrackGroup(new Format.Builder().build())))
+ .addOverride(
+ new TrackSelectionOverride(
+ new TrackGroup(
+ new Format.Builder().setId(4).build(),
+ new Format.Builder().setId(5).build()),
+ /* trackIndexes= */ ImmutableList.of(1)))
+ .build();
TrackSelectionParameters parameters =
TrackSelectionParameters.DEFAULT_WITHOUT_CONTEXT
.buildUpon()
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 40814ceffd..3e0ed7e887 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
@@ -39,7 +39,7 @@ import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.source.TrackGroupArray;
-import com.google.android.exoplayer2.trackselection.TrackSelectionParameters.TrackSelectionOverride;
+import com.google.android.exoplayer2.trackselection.TrackSelectionOverrides.TrackSelectionOverride;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.BundleableUtil;
import com.google.android.exoplayer2.util.Util;
@@ -611,7 +611,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
@Override
public ParametersBuilder setTrackSelectionOverrides(
- Map trackSelectionOverrides) {
+ TrackSelectionOverrides trackSelectionOverrides) {
super.setTrackSelectionOverrides(trackSelectionOverrides);
return this;
}
@@ -710,7 +710,9 @@ public class DefaultTrackSelector extends MappingTrackSelector {
* @param groups The {@link TrackGroupArray} for which the override should be applied.
* @param override The override.
* @return This builder.
+ * @deprecated Use {@link TrackSelectionParameters.Builder#setTrackSelectionOverrides}.
*/
+ @Deprecated
public final ParametersBuilder setSelectionOverride(
int rendererIndex, TrackGroupArray groups, @Nullable SelectionOverride override) {
Map overrides =
@@ -733,7 +735,9 @@ public class DefaultTrackSelector extends MappingTrackSelector {
* @param rendererIndex The renderer index.
* @param groups The {@link TrackGroupArray} for which the override should be cleared.
* @return This builder.
+ * @deprecated Use {@link TrackSelectionParameters.Builder#setTrackSelectionOverrides}.
*/
+ @Deprecated
public final ParametersBuilder clearSelectionOverride(
int rendererIndex, TrackGroupArray groups) {
Map overrides =
@@ -754,7 +758,9 @@ public class DefaultTrackSelector extends MappingTrackSelector {
*
* @param rendererIndex The renderer index.
* @return This builder.
+ * @deprecated Use {@link TrackSelectionParameters.Builder#setTrackSelectionOverrides}.
*/
+ @Deprecated
public final ParametersBuilder clearSelectionOverrides(int rendererIndex) {
Map overrides =
selectionOverrides.get(rendererIndex);
@@ -770,7 +776,9 @@ public class DefaultTrackSelector extends MappingTrackSelector {
* Clears all track selection overrides for all renderers.
*
* @return This builder.
+ * @deprecated Use {@link TrackSelectionParameters.Builder#setTrackSelectionOverrides}.
*/
+ @Deprecated
public final ParametersBuilder clearSelectionOverrides() {
if (selectionOverrides.size() == 0) {
// Nothing to clear.
@@ -1560,9 +1568,11 @@ public class DefaultTrackSelector extends MappingTrackSelector {
for (int j = 0; j < rendererTrackGroups.length; j++) {
TrackGroup trackGroup = rendererTrackGroups.get(j);
@Nullable
- TrackSelectionOverride overrideTracks = params.trackSelectionOverrides.get(trackGroup);
+ TrackSelectionOverride overrideTracks =
+ params.trackSelectionOverrides.getOverride(trackGroup);
if (overrideTracks != null) {
- return new ExoTrackSelection.Definition(trackGroup, Ints.toArray(overrideTracks.tracks));
+ return new ExoTrackSelection.Definition(
+ trackGroup, Ints.toArray(overrideTracks.trackIndexes));
}
}
return currentDefinition; // No override
diff --git a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelectionUtil.java b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelectionUtil.java
index 42f0ca68a0..a06d15b5cf 100644
--- a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelectionUtil.java
+++ b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelectionUtil.java
@@ -17,21 +17,11 @@ package com.google.android.exoplayer2.trackselection;
import android.os.SystemClock;
import androidx.annotation.Nullable;
-import com.google.android.exoplayer2.C;
-import com.google.android.exoplayer2.TracksInfo;
-import com.google.android.exoplayer2.TracksInfo.TrackGroupInfo;
-import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.SelectionOverride;
import com.google.android.exoplayer2.trackselection.ExoTrackSelection.Definition;
-import com.google.android.exoplayer2.trackselection.TrackSelectionParameters.TrackSelectionOverride;
import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy;
-import com.google.android.exoplayer2.util.MimeTypes;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import java.util.Map;
import org.checkerframework.checker.nullness.compatqual.NullableType;
-import org.checkerframework.dataflow.qual.Pure;
/** Track selection related utility methods. */
public final class TrackSelectionUtil {
@@ -134,67 +124,4 @@ public final class TrackSelectionUtil {
numberOfTracks,
numberOfExcludedTracks);
}
-
- /**
- * Forces tracks in a {@link TrackGroup} to be the only ones selected for a {@link C.TrackType}.
- * No other tracks of that type will be selectable. If the forced tracks are not supported, then
- * no tracks of that type will be selected.
- *
- * @param trackSelectionOverrides The current {@link TrackSelectionOverride overrides}.
- * @param tracksInfo The current {@link TracksInfo}.
- * @param forcedTrackGroupIndex The index of the {@link TrackGroup} in {@code tracksInfo} that
- * should have its track selected.
- * @param forcedTrackSelectionOverride The tracks to force selection of.
- * @return The updated {@link TrackSelectionOverride overrides}.
- */
- @Pure
- public static ImmutableMap forceTrackSelection(
- ImmutableMap trackSelectionOverrides,
- TracksInfo tracksInfo,
- int forcedTrackGroupIndex,
- TrackSelectionOverride forcedTrackSelectionOverride) {
- @C.TrackType
- int trackType = tracksInfo.getTrackGroupInfos().get(forcedTrackGroupIndex).getTrackType();
- ImmutableMap.Builder overridesBuilder =
- new ImmutableMap.Builder<>();
- // Maintain overrides for the other track types.
- for (Map.Entry entry : trackSelectionOverrides.entrySet()) {
- if (MimeTypes.getTrackType(entry.getKey().getFormat(0).sampleMimeType) != trackType) {
- overridesBuilder.put(entry);
- }
- }
- ImmutableList trackGroupInfos = tracksInfo.getTrackGroupInfos();
- for (int i = 0; i < trackGroupInfos.size(); i++) {
- TrackGroup trackGroup = trackGroupInfos.get(i).getTrackGroup();
- if (i == forcedTrackGroupIndex) {
- overridesBuilder.put(trackGroup, forcedTrackSelectionOverride);
- } else {
- overridesBuilder.put(trackGroup, TrackSelectionOverride.DISABLE);
- }
- }
- return overridesBuilder.build();
- }
-
- /**
- * Removes all {@link TrackSelectionOverride overrides} associated with {@link TrackGroup
- * TrackGroups} of type {@code trackType}.
- *
- * @param trackType The {@link C.TrackType} of all overrides to remove.
- * @param trackSelectionOverrides The current {@link TrackSelectionOverride overrides}.
- * @return The updated {@link TrackSelectionOverride overrides}.
- */
- @Pure
- public static ImmutableMap
- clearTrackSelectionOverridesForType(
- @C.TrackType int trackType,
- ImmutableMap trackSelectionOverrides) {
- ImmutableMap.Builder overridesBuilder =
- ImmutableMap.builder();
- for (Map.Entry entry : trackSelectionOverrides.entrySet()) {
- if (MimeTypes.getTrackType(entry.getKey().getFormat(0).sampleMimeType) != trackType) {
- overridesBuilder.put(entry);
- }
- }
- return overridesBuilder.build();
- }
}
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 e04a0530a7..0a12b61a12 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
@@ -46,13 +46,12 @@ import com.google.android.exoplayer2.testutil.FakeTimeline;
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.TrackSelectionParameters.TrackSelectionOverride;
+import com.google.android.exoplayer2.trackselection.TrackSelectionOverrides.TrackSelectionOverride;
import com.google.android.exoplayer2.trackselection.TrackSelector.InvalidationListener;
import com.google.android.exoplayer2.upstream.BandwidthMeter;
import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.Util;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import java.util.HashMap;
import java.util.Map;
@@ -158,12 +157,15 @@ public final class DefaultTrackSelectorTest {
/** Tests that an empty override clears a track selection. */
@Test
- public void selectTracks_withNullOverride_clearsTrackSelection() throws ExoPlaybackException {
+ public void selectTracks_withOverrideWithoutTracks_clearsTrackSelection()
+ throws ExoPlaybackException {
trackSelector.setParameters(
trackSelector
.buildUponParameters()
.setTrackSelectionOverrides(
- ImmutableMap.of(VIDEO_TRACK_GROUP, new TrackSelectionOverride(ImmutableSet.of()))));
+ new TrackSelectionOverrides.Builder()
+ .addOverride(new TrackSelectionOverride(VIDEO_TRACK_GROUP, ImmutableList.of()))
+ .build()));
TrackSelectorResult result =
trackSelector.selectTracks(RENDERER_CAPABILITIES, TRACK_GROUPS, periodId, TIMELINE);
@@ -210,8 +212,11 @@ public final class DefaultTrackSelectorTest {
trackSelector
.buildUponParameters()
.setTrackSelectionOverrides(
- ImmutableMap.of(
- new TrackGroup(VIDEO_FORMAT, VIDEO_FORMAT), TrackSelectionOverride.DISABLE)));
+ new TrackSelectionOverrides.Builder()
+ .setOverrideForType(
+ new TrackSelectionOverride(
+ new TrackGroup(VIDEO_FORMAT, VIDEO_FORMAT), ImmutableList.of()))
+ .build()));
TrackSelectorResult result =
trackSelector.selectTracks(
@@ -1874,9 +1879,12 @@ public final class DefaultTrackSelectorTest {
.setRendererDisabled(3, true)
.setRendererDisabled(5, false)
.setTrackSelectionOverrides(
- ImmutableMap.of(
- AUDIO_TRACK_GROUP,
- new TrackSelectionOverride(/* tracks= */ ImmutableSet.of(3, 4, 5))))
+ new TrackSelectionOverrides.Builder()
+ .setOverrideForType(
+ new TrackSelectionOverride(
+ new TrackGroup(AUDIO_FORMAT, AUDIO_FORMAT, AUDIO_FORMAT, AUDIO_FORMAT),
+ /* trackIndexes= */ ImmutableList.of(0, 2, 3)))
+ .build())
.setDisabledTrackTypes(ImmutableSet.of(C.TRACK_TYPE_AUDIO))
.build();
}
diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/StyledPlayerControlView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/StyledPlayerControlView.java
index 95dee700e5..30ca26f4f9 100644
--- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/StyledPlayerControlView.java
+++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/StyledPlayerControlView.java
@@ -32,9 +32,8 @@ import static com.google.android.exoplayer2.Player.EVENT_SEEK_FORWARD_INCREMENT_
import static com.google.android.exoplayer2.Player.EVENT_SHUFFLE_MODE_ENABLED_CHANGED;
import static com.google.android.exoplayer2.Player.EVENT_TIMELINE_CHANGED;
import static com.google.android.exoplayer2.Player.EVENT_TRACKS_CHANGED;
-import static com.google.android.exoplayer2.trackselection.TrackSelectionUtil.clearTrackSelectionOverridesForType;
-import static com.google.android.exoplayer2.trackselection.TrackSelectionUtil.forceTrackSelection;
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
+import static com.google.android.exoplayer2.util.Util.castNonNull;
import android.annotation.SuppressLint;
import android.content.Context;
@@ -68,13 +67,13 @@ import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.TracksInfo;
import com.google.android.exoplayer2.TracksInfo.TrackGroupInfo;
import com.google.android.exoplayer2.source.TrackGroup;
+import com.google.android.exoplayer2.trackselection.TrackSelectionOverrides;
+import com.google.android.exoplayer2.trackselection.TrackSelectionOverrides.TrackSelectionOverride;
import com.google.android.exoplayer2.trackselection.TrackSelectionParameters;
-import com.google.android.exoplayer2.trackselection.TrackSelectionParameters.TrackSelectionOverride;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.RepeatModeUtil;
import com.google.android.exoplayer2.util.Util;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import java.util.ArrayList;
import java.util.Arrays;
@@ -82,8 +81,8 @@ import java.util.Collections;
import java.util.Formatter;
import java.util.List;
import java.util.Locale;
-import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
+import org.checkerframework.dataflow.qual.Pure;
/**
* A view for controlling {@link Player} instances.
@@ -2032,14 +2031,8 @@ public class StyledPlayerControlView extends FrameLayout {
// Audio track selection option includes "Auto" at the top.
holder.textView.setText(R.string.exo_track_selection_auto);
// hasSelectionOverride is true means there is an explicit track selection, not "Auto".
- boolean hasSelectionOverride = false;
TrackSelectionParameters parameters = checkNotNull(player).getTrackSelectionParameters();
- for (int i = 0; i < tracks.size(); i++) {
- if (parameters.trackSelectionOverrides.containsKey(tracks.get(i).trackGroup)) {
- hasSelectionOverride = true;
- break;
- }
- }
+ boolean hasSelectionOverride = hasSelectionOverride(parameters.trackSelectionOverrides);
holder.checkView.setVisibility(hasSelectionOverride ? INVISIBLE : VISIBLE);
holder.itemView.setOnClickListener(
v -> {
@@ -2048,15 +2041,18 @@ public class StyledPlayerControlView extends FrameLayout {
}
TrackSelectionParameters trackSelectionParameters =
player.getTrackSelectionParameters();
- // Remove all audio overrides.
- ImmutableMap trackSelectionOverrides =
- clearTrackSelectionOverridesForType(
- C.TRACK_TYPE_AUDIO, trackSelectionParameters.trackSelectionOverrides);
- player.setTrackSelectionParameters(
+ TrackSelectionOverrides trackSelectionOverrides =
trackSelectionParameters
+ .trackSelectionOverrides
.buildUpon()
- .setTrackSelectionOverrides(trackSelectionOverrides)
- .build());
+ .clearOverridesOfType(C.TRACK_TYPE_AUDIO)
+ .build();
+ castNonNull(player)
+ .setTrackSelectionParameters(
+ trackSelectionParameters
+ .buildUpon()
+ .setTrackSelectionOverrides(trackSelectionOverrides)
+ .build());
settingsAdapter.setSubTextAtPosition(
SETTINGS_AUDIO_TRACK_SELECTION_POSITION,
getResources().getString(R.string.exo_track_selection_auto));
@@ -2064,6 +2060,21 @@ public class StyledPlayerControlView extends FrameLayout {
});
}
+ private boolean hasSelectionOverride(TrackSelectionOverrides trackSelectionOverrides) {
+ int previousTrackGroupIndex = C.INDEX_UNSET;
+ for (int i = 0; i < tracks.size(); i++) {
+ TrackInformation track = tracks.get(i);
+ if (track.trackGroupIndex == previousTrackGroupIndex) {
+ continue;
+ }
+ if (trackSelectionOverrides.getOverride(track.trackGroup) != null) {
+ return true;
+ }
+ previousTrackGroupIndex = track.trackGroupIndex;
+ }
+ return false;
+ }
+
@Override
public void onTrackSelection(String subtext) {
settingsAdapter.setSubTextAtPosition(SETTINGS_AUDIO_TRACK_SELECTION_POSITION, subtext);
@@ -2075,9 +2086,10 @@ public class StyledPlayerControlView extends FrameLayout {
boolean hasSelectionOverride = false;
for (int i = 0; i < trackInformations.size(); i++) {
if (checkNotNull(player)
- .getTrackSelectionParameters()
- .trackSelectionOverrides
- .containsKey(trackInformations.get(i).trackGroup)) {
+ .getTrackSelectionParameters()
+ .trackSelectionOverrides
+ .getOverride(trackInformations.get(i).trackGroup)
+ != null) {
hasSelectionOverride = true;
break;
}
@@ -2140,9 +2152,10 @@ public class StyledPlayerControlView extends FrameLayout {
TrackInformation track = tracks.get(position - 1);
boolean explicitlySelected =
checkNotNull(player)
- .getTrackSelectionParameters()
- .trackSelectionOverrides
- .containsKey(track.trackGroup)
+ .getTrackSelectionParameters()
+ .trackSelectionOverrides
+ .getOverride(track.trackGroup)
+ != null
&& track.isSelected();
holder.textView.setText(track.trackName);
holder.checkView.setVisibility(explicitlySelected ? VISIBLE : INVISIBLE);
@@ -2153,12 +2166,13 @@ public class StyledPlayerControlView extends FrameLayout {
}
TrackSelectionParameters trackSelectionParameters =
player.getTrackSelectionParameters();
- Map overrides =
+ TrackSelectionOverrides overrides =
forceTrackSelection(
trackSelectionParameters.trackSelectionOverrides,
track.tracksInfo,
track.trackGroupIndex,
- new TrackSelectionOverride(ImmutableSet.of(track.trackIndex)));
+ new TrackSelectionOverride(
+ track.trackGroup, ImmutableList.of(track.trackIndex)));
checkNotNull(player)
.setTrackSelectionParameters(
trackSelectionParameters
@@ -2196,4 +2210,41 @@ public class StyledPlayerControlView extends FrameLayout {
checkView = itemView.findViewById(R.id.exo_check);
}
}
+
+ /**
+ * Forces tracks in a {@link TrackGroup} to be the only ones selected for a {@link C.TrackType}.
+ * No other tracks of that type will be selectable. If the forced tracks are not supported, then
+ * no tracks of that type will be selected.
+ *
+ * @param trackSelectionOverrides The current {@link TrackSelectionOverride overrides}.
+ * @param tracksInfo The current {@link TracksInfo}.
+ * @param forcedTrackGroupIndex The index of the {@link TrackGroup} in {@code tracksInfo} that
+ * should have its track selected.
+ * @param forcedTrackSelectionOverride The tracks to force selection of.
+ * @return The updated {@link TrackSelectionOverride overrides}.
+ */
+ @Pure
+ private static TrackSelectionOverrides forceTrackSelection(
+ TrackSelectionOverrides trackSelectionOverrides,
+ TracksInfo tracksInfo,
+ int forcedTrackGroupIndex,
+ TrackSelectionOverride forcedTrackSelectionOverride) {
+ TrackSelectionOverrides.Builder overridesBuilder = trackSelectionOverrides.buildUpon();
+
+ @C.TrackType
+ int trackType = tracksInfo.getTrackGroupInfos().get(forcedTrackGroupIndex).getTrackType();
+ overridesBuilder.setOverrideForType(forcedTrackSelectionOverride);
+ // TrackSelectionOverride doesn't currently guarantee that only overwritten track
+ // group of a given type are selected, so the others have to be explicitly disabled.
+ // This guarantee is provided in the following patch that removes the need for this method.
+ ImmutableList trackGroupInfos = tracksInfo.getTrackGroupInfos();
+ for (int i = 0; i < trackGroupInfos.size(); i++) {
+ TrackGroupInfo trackGroupInfo = trackGroupInfos.get(i);
+ if (i != forcedTrackGroupIndex && trackGroupInfo.getTrackType() == trackType) {
+ TrackGroup trackGroup = trackGroupInfo.getTrackGroup();
+ overridesBuilder.addOverride(new TrackSelectionOverride(trackGroup, ImmutableList.of()));
+ }
+ }
+ return overridesBuilder.build();
+ }
}