Commit 1f3f22a7 by krocard Committed by Oliver Woodman

Encapsulate TrackSelectionOverrides in its own class

The current API exposes an `ImmutableMap` of
`TrackGroup` -> `TrackSelectionOverride`.
This has several disadvantages:
 - A difficult to use API for mutation
   (`ImmutableMap.Builder` doesn't support key removal).
 - There is no track selection specific methods,
   how the generic map API mapps to the selection override is not complex
   but to obvious for a casual reader.
 - The internal data type is exposed, making internal refactor difficult.

This was done to have the API ready as quick as possible.

When transitioning the clients to the map API in <unknown commit>,
it became clear that the map API was too verbose and not mapping
to the clients needs, so utility methods
were added to make operations clearer and more concise.

Nevertheless, having to use utility method to use easily and correctly
an API is not the sign of a good API.

This cl refactors the track selection API for several improvements:

 - Add a type `TrackSelectionParameters` that encapsulate the internal
   data structure (map currently).
 - For iteration, expose as a list.
 - Add a `Builder` for easy mutable operations.
 - Add track selection specific methods to avoid having utilities functions.
 - Those operations are the same as `DefaultTrackSelector.Parameters`
   for easier migration. (`setOverride` was renamed to `addOverride`)
 - Move `TrackSelection` classes outside of `TrackSelectionParameters`
   as their own top level classes.

The migration of the client code is straightforward as most of it
were already using the previously mentioned utility functions
that are now native methods.

The full migration has not been done yet, and is pending on this cl approval.

PiperOrigin-RevId: 405362719
parent 2ee72076
...@@ -16,8 +16,7 @@ ...@@ -16,8 +16,7 @@
package com.google.android.exoplayer2.trackselection; package com.google.android.exoplayer2.trackselection;
import static com.google.android.exoplayer2.util.Assertions.checkNotNull; 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.fromNullableBundle;
import static com.google.android.exoplayer2.util.BundleableUtil.toBundleArrayList;
import static com.google.common.base.MoreObjects.firstNonNull; import static com.google.common.base.MoreObjects.firstNonNull;
import android.content.Context; import android.content.Context;
...@@ -30,23 +29,17 @@ import androidx.annotation.Nullable; ...@@ -30,23 +29,17 @@ import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi; import androidx.annotation.RequiresApi;
import com.google.android.exoplayer2.Bundleable; import com.google.android.exoplayer2.Bundleable;
import com.google.android.exoplayer2.C; 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.android.exoplayer2.util.Util;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import com.google.common.primitives.Ints; import com.google.common.primitives.Ints;
import java.lang.annotation.Documented; import java.lang.annotation.Documented;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map;
import java.util.Set; import java.util.Set;
import org.checkerframework.checker.initialization.qual.UnknownInitialization; import org.checkerframework.checker.initialization.qual.UnknownInitialization;
import org.checkerframework.checker.nullness.qual.EnsuresNonNull; import org.checkerframework.checker.nullness.qual.EnsuresNonNull;
import org.checkerframework.checker.nullness.qual.NonNull;
/** /**
* Constraint parameters for track selection. * Constraint parameters for track selection.
...@@ -100,7 +93,7 @@ public class TrackSelectionParameters implements Bundleable { ...@@ -100,7 +93,7 @@ public class TrackSelectionParameters implements Bundleable {
// General // General
private boolean forceLowestBitrate; private boolean forceLowestBitrate;
private boolean forceHighestSupportedBitrate; private boolean forceHighestSupportedBitrate;
private ImmutableMap<TrackGroup, TrackSelectionOverride> trackSelectionOverrides; private TrackSelectionOverrides trackSelectionOverrides;
private ImmutableSet<@C.TrackType Integer> disabledTrackTypes; private ImmutableSet<@C.TrackType Integer> disabledTrackTypes;
/** /**
...@@ -131,7 +124,7 @@ public class TrackSelectionParameters implements Bundleable { ...@@ -131,7 +124,7 @@ public class TrackSelectionParameters implements Bundleable {
// General // General
forceLowestBitrate = false; forceLowestBitrate = false;
forceHighestSupportedBitrate = false; forceHighestSupportedBitrate = false;
trackSelectionOverrides = ImmutableMap.of(); trackSelectionOverrides = TrackSelectionOverrides.EMPTY;
disabledTrackTypes = ImmutableSet.of(); disabledTrackTypes = ImmutableSet.of();
} }
...@@ -233,17 +226,11 @@ public class TrackSelectionParameters implements Bundleable { ...@@ -233,17 +226,11 @@ public class TrackSelectionParameters implements Bundleable {
bundle.getBoolean( bundle.getBoolean(
keyForField(FIELD_FORCE_HIGHEST_SUPPORTED_BITRATE), keyForField(FIELD_FORCE_HIGHEST_SUPPORTED_BITRATE),
DEFAULT_WITHOUT_CONTEXT.forceHighestSupportedBitrate); DEFAULT_WITHOUT_CONTEXT.forceHighestSupportedBitrate);
List<TrackGroup> keys = trackSelectionOverrides =
fromBundleNullableList( fromNullableBundle(
TrackGroup.CREATOR, TrackSelectionOverrides.CREATOR,
bundle.getParcelableArrayList(keyForField(FIELD_SELECTION_OVERRIDE_KEYS)), bundle.getBundle(keyForField(FIELD_SELECTION_OVERRIDE_KEYS)),
ImmutableList.of()); TrackSelectionOverrides.EMPTY);
List<TrackSelectionOverride> values =
fromBundleNullableList(
TrackSelectionOverride.CREATOR,
bundle.getParcelableArrayList(keyForField(FIELD_SELECTION_OVERRIDE_VALUES)),
ImmutableList.of());
trackSelectionOverrides = zipToMap(keys, values);
disabledTrackTypes = disabledTrackTypes =
ImmutableSet.copyOf( ImmutableSet.copyOf(
Ints.asList( Ints.asList(
...@@ -642,9 +629,8 @@ public class TrackSelectionParameters implements Bundleable { ...@@ -642,9 +629,8 @@ public class TrackSelectionParameters implements Bundleable {
* @param trackSelectionOverrides The track selection overrides. * @param trackSelectionOverrides The track selection overrides.
* @return This builder. * @return This builder.
*/ */
public Builder setTrackSelectionOverrides( public Builder setTrackSelectionOverrides(TrackSelectionOverrides trackSelectionOverrides) {
Map<TrackGroup, TrackSelectionOverride> trackSelectionOverrides) { this.trackSelectionOverrides = trackSelectionOverrides;
this.trackSelectionOverrides = ImmutableMap.copyOf(trackSelectionOverrides);
return this; return this;
} }
...@@ -692,83 +678,6 @@ public class TrackSelectionParameters implements Bundleable { ...@@ -692,83 +678,6 @@ public class TrackSelectionParameters implements Bundleable {
} }
return listBuilder.build(); return listBuilder.build();
} }
private static <K, V> 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<Integer> tracks;
/** Constructs an instance to force {@code tracks} to be selected. */
public TrackSelectionOverride(ImmutableSet<Integer> 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<TrackSelectionOverride> 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 { ...@@ -921,29 +830,8 @@ public class TrackSelectionParameters implements Bundleable {
*/ */
public final boolean forceHighestSupportedBitrate; public final boolean forceHighestSupportedBitrate;
/** /** Overrides to force tracks to be selected. */
* For each {@link TrackGroup} in the map, forces the tracks associated with it to be selected for public final TrackSelectionOverrides trackSelectionOverrides;
* playback.
*
* <p>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.
*
* <p>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.
*
* <p>If multiple tracks of the {@link TrackGroup} are overriden, all supported (see {@link
* C.FormatSupport}) will be selected.
*
* <p>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.
*
* <p>The default value is that no {@link TrackGroup} selections are overridden (empty map).
*/
public final ImmutableMap<TrackGroup, TrackSelectionOverride> trackSelectionOverrides;
/** /**
* The track types that are disabled. No track of a disabled type will be selected, thus no track * 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 * 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 { ...@@ -1159,12 +1047,8 @@ public class TrackSelectionParameters implements Bundleable {
bundle.putBoolean(keyForField(FIELD_FORCE_LOWEST_BITRATE), forceLowestBitrate); bundle.putBoolean(keyForField(FIELD_FORCE_LOWEST_BITRATE), forceLowestBitrate);
bundle.putBoolean( bundle.putBoolean(
keyForField(FIELD_FORCE_HIGHEST_SUPPORTED_BITRATE), forceHighestSupportedBitrate); keyForField(FIELD_FORCE_HIGHEST_SUPPORTED_BITRATE), forceHighestSupportedBitrate);
bundle.putParcelableArrayList( bundle.putBundle(
keyForField(FIELD_SELECTION_OVERRIDE_KEYS), keyForField(FIELD_SELECTION_OVERRIDE_KEYS), trackSelectionOverrides.toBundle());
toBundleArrayList(trackSelectionOverrides.keySet()));
bundle.putParcelableArrayList(
keyForField(FIELD_SELECTION_OVERRIDE_VALUES),
toBundleArrayList(trackSelectionOverrides.values()));
bundle.putIntArray(keyForField(FIELD_DISABLED_TRACK_TYPE), Ints.toArray(disabledTrackTypes)); bundle.putIntArray(keyForField(FIELD_DISABLED_TRACK_TYPE), Ints.toArray(disabledTrackTypes));
return bundle; return bundle;
......
/*
* 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);
}
}
...@@ -23,16 +23,16 @@ import com.google.android.exoplayer2.Bundleable; ...@@ -23,16 +23,16 @@ import com.google.android.exoplayer2.Bundleable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.SelectionOverride; 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.android.exoplayer2.util.MimeTypes;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
/** Tests for {@link TrackSelectionParameters}. */ /** Tests for {@link TrackSelectionParameters}. */
@RunWith(AndroidJUnit4.class) @RunWith(AndroidJUnit4.class)
public class TrackSelectionParametersTest { public final class TrackSelectionParametersTest {
@Test @Test
public void defaultValue_withoutChange_isAsExpected() { public void defaultValue_withoutChange_isAsExpected() {
...@@ -64,16 +64,22 @@ public class TrackSelectionParametersTest { ...@@ -64,16 +64,22 @@ public class TrackSelectionParametersTest {
// General // General
assertThat(parameters.forceLowestBitrate).isFalse(); assertThat(parameters.forceLowestBitrate).isFalse();
assertThat(parameters.forceHighestSupportedBitrate).isFalse(); assertThat(parameters.forceHighestSupportedBitrate).isFalse();
assertThat(parameters.trackSelectionOverrides).isEmpty(); assertThat(parameters.trackSelectionOverrides.asList()).isEmpty();
assertThat(parameters.disabledTrackTypes).isEmpty(); assertThat(parameters.disabledTrackTypes).isEmpty();
} }
@Test @Test
public void parametersSet_fromDefault_isAsExpected() { public void parametersSet_fromDefault_isAsExpected() {
ImmutableMap<TrackGroup, TrackSelectionOverride> trackSelectionOverrides = TrackSelectionOverrides trackSelectionOverrides =
ImmutableMap.of( new TrackSelectionOverrides.Builder()
new TrackGroup(new Format.Builder().build()), .addOverride(new TrackSelectionOverride(new TrackGroup(new Format.Builder().build())))
new TrackSelectionOverride(/* tracks= */ ImmutableSet.of(2, 3))); .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 parameters =
TrackSelectionParameters.DEFAULT_WITHOUT_CONTEXT TrackSelectionParameters.DEFAULT_WITHOUT_CONTEXT
.buildUpon() .buildUpon()
......
...@@ -39,7 +39,7 @@ import com.google.android.exoplayer2.Timeline; ...@@ -39,7 +39,7 @@ import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
import com.google.android.exoplayer2.source.TrackGroup; import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.source.TrackGroupArray; 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.Assertions;
import com.google.android.exoplayer2.util.BundleableUtil; import com.google.android.exoplayer2.util.BundleableUtil;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
...@@ -611,7 +611,7 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -611,7 +611,7 @@ public class DefaultTrackSelector extends MappingTrackSelector {
@Override @Override
public ParametersBuilder setTrackSelectionOverrides( public ParametersBuilder setTrackSelectionOverrides(
Map<TrackGroup, TrackSelectionOverride> trackSelectionOverrides) { TrackSelectionOverrides trackSelectionOverrides) {
super.setTrackSelectionOverrides(trackSelectionOverrides); super.setTrackSelectionOverrides(trackSelectionOverrides);
return this; return this;
} }
...@@ -710,7 +710,9 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -710,7 +710,9 @@ public class DefaultTrackSelector extends MappingTrackSelector {
* @param groups The {@link TrackGroupArray} for which the override should be applied. * @param groups The {@link TrackGroupArray} for which the override should be applied.
* @param override The override. * @param override The override.
* @return This builder. * @return This builder.
* @deprecated Use {@link TrackSelectionParameters.Builder#setTrackSelectionOverrides}.
*/ */
@Deprecated
public final ParametersBuilder setSelectionOverride( public final ParametersBuilder setSelectionOverride(
int rendererIndex, TrackGroupArray groups, @Nullable SelectionOverride override) { int rendererIndex, TrackGroupArray groups, @Nullable SelectionOverride override) {
Map<TrackGroupArray, @NullableType SelectionOverride> overrides = Map<TrackGroupArray, @NullableType SelectionOverride> overrides =
...@@ -733,7 +735,9 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -733,7 +735,9 @@ public class DefaultTrackSelector extends MappingTrackSelector {
* @param rendererIndex The renderer index. * @param rendererIndex The renderer index.
* @param groups The {@link TrackGroupArray} for which the override should be cleared. * @param groups The {@link TrackGroupArray} for which the override should be cleared.
* @return This builder. * @return This builder.
* @deprecated Use {@link TrackSelectionParameters.Builder#setTrackSelectionOverrides}.
*/ */
@Deprecated
public final ParametersBuilder clearSelectionOverride( public final ParametersBuilder clearSelectionOverride(
int rendererIndex, TrackGroupArray groups) { int rendererIndex, TrackGroupArray groups) {
Map<TrackGroupArray, @NullableType SelectionOverride> overrides = Map<TrackGroupArray, @NullableType SelectionOverride> overrides =
...@@ -754,7 +758,9 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -754,7 +758,9 @@ public class DefaultTrackSelector extends MappingTrackSelector {
* *
* @param rendererIndex The renderer index. * @param rendererIndex The renderer index.
* @return This builder. * @return This builder.
* @deprecated Use {@link TrackSelectionParameters.Builder#setTrackSelectionOverrides}.
*/ */
@Deprecated
public final ParametersBuilder clearSelectionOverrides(int rendererIndex) { public final ParametersBuilder clearSelectionOverrides(int rendererIndex) {
Map<TrackGroupArray, @NullableType SelectionOverride> overrides = Map<TrackGroupArray, @NullableType SelectionOverride> overrides =
selectionOverrides.get(rendererIndex); selectionOverrides.get(rendererIndex);
...@@ -770,7 +776,9 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -770,7 +776,9 @@ public class DefaultTrackSelector extends MappingTrackSelector {
* Clears all track selection overrides for all renderers. * Clears all track selection overrides for all renderers.
* *
* @return This builder. * @return This builder.
* @deprecated Use {@link TrackSelectionParameters.Builder#setTrackSelectionOverrides}.
*/ */
@Deprecated
public final ParametersBuilder clearSelectionOverrides() { public final ParametersBuilder clearSelectionOverrides() {
if (selectionOverrides.size() == 0) { if (selectionOverrides.size() == 0) {
// Nothing to clear. // Nothing to clear.
...@@ -1560,9 +1568,11 @@ public class DefaultTrackSelector extends MappingTrackSelector { ...@@ -1560,9 +1568,11 @@ public class DefaultTrackSelector extends MappingTrackSelector {
for (int j = 0; j < rendererTrackGroups.length; j++) { for (int j = 0; j < rendererTrackGroups.length; j++) {
TrackGroup trackGroup = rendererTrackGroups.get(j); TrackGroup trackGroup = rendererTrackGroups.get(j);
@Nullable @Nullable
TrackSelectionOverride overrideTracks = params.trackSelectionOverrides.get(trackGroup); TrackSelectionOverride overrideTracks =
params.trackSelectionOverrides.getOverride(trackGroup);
if (overrideTracks != null) { 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 return currentDefinition; // No override
......
...@@ -17,21 +17,11 @@ package com.google.android.exoplayer2.trackselection; ...@@ -17,21 +17,11 @@ package com.google.android.exoplayer2.trackselection;
import android.os.SystemClock; import android.os.SystemClock;
import androidx.annotation.Nullable; 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.source.TrackGroupArray;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.SelectionOverride; import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.SelectionOverride;
import com.google.android.exoplayer2.trackselection.ExoTrackSelection.Definition; 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.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.checker.nullness.compatqual.NullableType;
import org.checkerframework.dataflow.qual.Pure;
/** Track selection related utility methods. */ /** Track selection related utility methods. */
public final class TrackSelectionUtil { public final class TrackSelectionUtil {
...@@ -134,67 +124,4 @@ public final class TrackSelectionUtil { ...@@ -134,67 +124,4 @@ public final class TrackSelectionUtil {
numberOfTracks, numberOfTracks,
numberOfExcludedTracks); 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<TrackGroup, TrackSelectionOverride> forceTrackSelection(
ImmutableMap<TrackGroup, TrackSelectionOverride> trackSelectionOverrides,
TracksInfo tracksInfo,
int forcedTrackGroupIndex,
TrackSelectionOverride forcedTrackSelectionOverride) {
@C.TrackType
int trackType = tracksInfo.getTrackGroupInfos().get(forcedTrackGroupIndex).getTrackType();
ImmutableMap.Builder<TrackGroup, TrackSelectionOverride> overridesBuilder =
new ImmutableMap.Builder<>();
// Maintain overrides for the other track types.
for (Map.Entry<TrackGroup, TrackSelectionOverride> entry : trackSelectionOverrides.entrySet()) {
if (MimeTypes.getTrackType(entry.getKey().getFormat(0).sampleMimeType) != trackType) {
overridesBuilder.put(entry);
}
}
ImmutableList<TrackGroupInfo> 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<TrackGroup, TrackSelectionOverride>
clearTrackSelectionOverridesForType(
@C.TrackType int trackType,
ImmutableMap<TrackGroup, TrackSelectionOverride> trackSelectionOverrides) {
ImmutableMap.Builder<TrackGroup, TrackSelectionOverride> overridesBuilder =
ImmutableMap.builder();
for (Map.Entry<TrackGroup, TrackSelectionOverride> entry : trackSelectionOverrides.entrySet()) {
if (MimeTypes.getTrackType(entry.getKey().getFormat(0).sampleMimeType) != trackType) {
overridesBuilder.put(entry);
}
}
return overridesBuilder.build();
}
} }
...@@ -46,13 +46,12 @@ import com.google.android.exoplayer2.testutil.FakeTimeline; ...@@ -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.Parameters;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.ParametersBuilder; import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.ParametersBuilder;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.SelectionOverride; import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.SelectionOverride;
import com.google.android.exoplayer2.trackselection.TrackSelectionParameters.TrackSelectionOverride; import com.google.android.exoplayer2.trackselection.TrackSelectionOverrides.TrackSelectionOverride;
import com.google.android.exoplayer2.trackselection.TrackSelector.InvalidationListener; import com.google.android.exoplayer2.trackselection.TrackSelector.InvalidationListener;
import com.google.android.exoplayer2.upstream.BandwidthMeter; import com.google.android.exoplayer2.upstream.BandwidthMeter;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
...@@ -158,12 +157,15 @@ public final class DefaultTrackSelectorTest { ...@@ -158,12 +157,15 @@ public final class DefaultTrackSelectorTest {
/** Tests that an empty override clears a track selection. */ /** Tests that an empty override clears a track selection. */
@Test @Test
public void selectTracks_withNullOverride_clearsTrackSelection() throws ExoPlaybackException { public void selectTracks_withOverrideWithoutTracks_clearsTrackSelection()
throws ExoPlaybackException {
trackSelector.setParameters( trackSelector.setParameters(
trackSelector trackSelector
.buildUponParameters() .buildUponParameters()
.setTrackSelectionOverrides( .setTrackSelectionOverrides(
ImmutableMap.of(VIDEO_TRACK_GROUP, new TrackSelectionOverride(ImmutableSet.of())))); new TrackSelectionOverrides.Builder()
.addOverride(new TrackSelectionOverride(VIDEO_TRACK_GROUP, ImmutableList.of()))
.build()));
TrackSelectorResult result = TrackSelectorResult result =
trackSelector.selectTracks(RENDERER_CAPABILITIES, TRACK_GROUPS, periodId, TIMELINE); trackSelector.selectTracks(RENDERER_CAPABILITIES, TRACK_GROUPS, periodId, TIMELINE);
...@@ -210,8 +212,11 @@ public final class DefaultTrackSelectorTest { ...@@ -210,8 +212,11 @@ public final class DefaultTrackSelectorTest {
trackSelector trackSelector
.buildUponParameters() .buildUponParameters()
.setTrackSelectionOverrides( .setTrackSelectionOverrides(
ImmutableMap.of( new TrackSelectionOverrides.Builder()
new TrackGroup(VIDEO_FORMAT, VIDEO_FORMAT), TrackSelectionOverride.DISABLE))); .setOverrideForType(
new TrackSelectionOverride(
new TrackGroup(VIDEO_FORMAT, VIDEO_FORMAT), ImmutableList.of()))
.build()));
TrackSelectorResult result = TrackSelectorResult result =
trackSelector.selectTracks( trackSelector.selectTracks(
...@@ -1874,9 +1879,12 @@ public final class DefaultTrackSelectorTest { ...@@ -1874,9 +1879,12 @@ public final class DefaultTrackSelectorTest {
.setRendererDisabled(3, true) .setRendererDisabled(3, true)
.setRendererDisabled(5, false) .setRendererDisabled(5, false)
.setTrackSelectionOverrides( .setTrackSelectionOverrides(
ImmutableMap.of( new TrackSelectionOverrides.Builder()
AUDIO_TRACK_GROUP, .setOverrideForType(
new TrackSelectionOverride(/* tracks= */ ImmutableSet.of(3, 4, 5)))) 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)) .setDisabledTrackTypes(ImmutableSet.of(C.TRACK_TYPE_AUDIO))
.build(); .build();
} }
......
...@@ -32,9 +32,8 @@ import static com.google.android.exoplayer2.Player.EVENT_SEEK_FORWARD_INCREMENT_ ...@@ -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_SHUFFLE_MODE_ENABLED_CHANGED;
import static com.google.android.exoplayer2.Player.EVENT_TIMELINE_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.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.Assertions.checkNotNull;
import static com.google.android.exoplayer2.util.Util.castNonNull;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.content.Context; import android.content.Context;
...@@ -68,13 +67,13 @@ import com.google.android.exoplayer2.Timeline; ...@@ -68,13 +67,13 @@ import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.TracksInfo; import com.google.android.exoplayer2.TracksInfo;
import com.google.android.exoplayer2.TracksInfo.TrackGroupInfo; import com.google.android.exoplayer2.TracksInfo.TrackGroupInfo;
import com.google.android.exoplayer2.source.TrackGroup; 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;
import com.google.android.exoplayer2.trackselection.TrackSelectionParameters.TrackSelectionOverride;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.RepeatModeUtil; import com.google.android.exoplayer2.util.RepeatModeUtil;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
...@@ -82,8 +81,8 @@ import java.util.Collections; ...@@ -82,8 +81,8 @@ import java.util.Collections;
import java.util.Formatter; import java.util.Formatter;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import org.checkerframework.dataflow.qual.Pure;
/** /**
* A view for controlling {@link Player} instances. * A view for controlling {@link Player} instances.
...@@ -2032,14 +2031,8 @@ public class StyledPlayerControlView extends FrameLayout { ...@@ -2032,14 +2031,8 @@ public class StyledPlayerControlView extends FrameLayout {
// Audio track selection option includes "Auto" at the top. // Audio track selection option includes "Auto" at the top.
holder.textView.setText(R.string.exo_track_selection_auto); holder.textView.setText(R.string.exo_track_selection_auto);
// hasSelectionOverride is true means there is an explicit track selection, not "Auto". // hasSelectionOverride is true means there is an explicit track selection, not "Auto".
boolean hasSelectionOverride = false;
TrackSelectionParameters parameters = checkNotNull(player).getTrackSelectionParameters(); TrackSelectionParameters parameters = checkNotNull(player).getTrackSelectionParameters();
for (int i = 0; i < tracks.size(); i++) { boolean hasSelectionOverride = hasSelectionOverride(parameters.trackSelectionOverrides);
if (parameters.trackSelectionOverrides.containsKey(tracks.get(i).trackGroup)) {
hasSelectionOverride = true;
break;
}
}
holder.checkView.setVisibility(hasSelectionOverride ? INVISIBLE : VISIBLE); holder.checkView.setVisibility(hasSelectionOverride ? INVISIBLE : VISIBLE);
holder.itemView.setOnClickListener( holder.itemView.setOnClickListener(
v -> { v -> {
...@@ -2048,15 +2041,18 @@ public class StyledPlayerControlView extends FrameLayout { ...@@ -2048,15 +2041,18 @@ public class StyledPlayerControlView extends FrameLayout {
} }
TrackSelectionParameters trackSelectionParameters = TrackSelectionParameters trackSelectionParameters =
player.getTrackSelectionParameters(); player.getTrackSelectionParameters();
// Remove all audio overrides. TrackSelectionOverrides trackSelectionOverrides =
ImmutableMap<TrackGroup, TrackSelectionOverride> trackSelectionOverrides =
clearTrackSelectionOverridesForType(
C.TRACK_TYPE_AUDIO, trackSelectionParameters.trackSelectionOverrides);
player.setTrackSelectionParameters(
trackSelectionParameters trackSelectionParameters
.trackSelectionOverrides
.buildUpon() .buildUpon()
.setTrackSelectionOverrides(trackSelectionOverrides) .clearOverridesOfType(C.TRACK_TYPE_AUDIO)
.build()); .build();
castNonNull(player)
.setTrackSelectionParameters(
trackSelectionParameters
.buildUpon()
.setTrackSelectionOverrides(trackSelectionOverrides)
.build());
settingsAdapter.setSubTextAtPosition( settingsAdapter.setSubTextAtPosition(
SETTINGS_AUDIO_TRACK_SELECTION_POSITION, SETTINGS_AUDIO_TRACK_SELECTION_POSITION,
getResources().getString(R.string.exo_track_selection_auto)); getResources().getString(R.string.exo_track_selection_auto));
...@@ -2064,6 +2060,21 @@ public class StyledPlayerControlView extends FrameLayout { ...@@ -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 @Override
public void onTrackSelection(String subtext) { public void onTrackSelection(String subtext) {
settingsAdapter.setSubTextAtPosition(SETTINGS_AUDIO_TRACK_SELECTION_POSITION, subtext); settingsAdapter.setSubTextAtPosition(SETTINGS_AUDIO_TRACK_SELECTION_POSITION, subtext);
...@@ -2075,9 +2086,10 @@ public class StyledPlayerControlView extends FrameLayout { ...@@ -2075,9 +2086,10 @@ public class StyledPlayerControlView extends FrameLayout {
boolean hasSelectionOverride = false; boolean hasSelectionOverride = false;
for (int i = 0; i < trackInformations.size(); i++) { for (int i = 0; i < trackInformations.size(); i++) {
if (checkNotNull(player) if (checkNotNull(player)
.getTrackSelectionParameters() .getTrackSelectionParameters()
.trackSelectionOverrides .trackSelectionOverrides
.containsKey(trackInformations.get(i).trackGroup)) { .getOverride(trackInformations.get(i).trackGroup)
!= null) {
hasSelectionOverride = true; hasSelectionOverride = true;
break; break;
} }
...@@ -2140,9 +2152,10 @@ public class StyledPlayerControlView extends FrameLayout { ...@@ -2140,9 +2152,10 @@ public class StyledPlayerControlView extends FrameLayout {
TrackInformation track = tracks.get(position - 1); TrackInformation track = tracks.get(position - 1);
boolean explicitlySelected = boolean explicitlySelected =
checkNotNull(player) checkNotNull(player)
.getTrackSelectionParameters() .getTrackSelectionParameters()
.trackSelectionOverrides .trackSelectionOverrides
.containsKey(track.trackGroup) .getOverride(track.trackGroup)
!= null
&& track.isSelected(); && track.isSelected();
holder.textView.setText(track.trackName); holder.textView.setText(track.trackName);
holder.checkView.setVisibility(explicitlySelected ? VISIBLE : INVISIBLE); holder.checkView.setVisibility(explicitlySelected ? VISIBLE : INVISIBLE);
...@@ -2153,12 +2166,13 @@ public class StyledPlayerControlView extends FrameLayout { ...@@ -2153,12 +2166,13 @@ public class StyledPlayerControlView extends FrameLayout {
} }
TrackSelectionParameters trackSelectionParameters = TrackSelectionParameters trackSelectionParameters =
player.getTrackSelectionParameters(); player.getTrackSelectionParameters();
Map<TrackGroup, TrackSelectionOverride> overrides = TrackSelectionOverrides overrides =
forceTrackSelection( forceTrackSelection(
trackSelectionParameters.trackSelectionOverrides, trackSelectionParameters.trackSelectionOverrides,
track.tracksInfo, track.tracksInfo,
track.trackGroupIndex, track.trackGroupIndex,
new TrackSelectionOverride(ImmutableSet.of(track.trackIndex))); new TrackSelectionOverride(
track.trackGroup, ImmutableList.of(track.trackIndex)));
checkNotNull(player) checkNotNull(player)
.setTrackSelectionParameters( .setTrackSelectionParameters(
trackSelectionParameters trackSelectionParameters
...@@ -2196,4 +2210,41 @@ public class StyledPlayerControlView extends FrameLayout { ...@@ -2196,4 +2210,41 @@ public class StyledPlayerControlView extends FrameLayout {
checkView = itemView.findViewById(R.id.exo_check); 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<TrackGroupInfo> 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();
}
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment