Rename TracksInfo and TrackGroupInfo

1. TracksInfo is renamed to Tracks
2. TracksInfo.TrackGroupInfo is renamed to Tracks.Group

PiperOrigin-RevId: 441232373
This commit is contained in:
olly 2022-04-12 18:47:49 +01:00 committed by Ian Baker
parent 3f47c1ead3
commit 0ad508b14f
40 changed files with 600 additions and 605 deletions

View File

@ -25,7 +25,7 @@ import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Player.DiscontinuityReason; import com.google.android.exoplayer2.Player.DiscontinuityReason;
import com.google.android.exoplayer2.Player.TimelineChangeReason; import com.google.android.exoplayer2.Player.TimelineChangeReason;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.TracksInfo; import com.google.android.exoplayer2.Tracks;
import com.google.android.exoplayer2.ext.cast.CastPlayer; import com.google.android.exoplayer2.ext.cast.CastPlayer;
import com.google.android.exoplayer2.ext.cast.SessionAvailabilityListener; import com.google.android.exoplayer2.ext.cast.SessionAvailabilityListener;
import com.google.android.exoplayer2.ui.StyledPlayerControlView; import com.google.android.exoplayer2.ui.StyledPlayerControlView;
@ -57,7 +57,7 @@ import java.util.ArrayList;
private final ArrayList<MediaItem> mediaQueue; private final ArrayList<MediaItem> mediaQueue;
private final Listener listener; private final Listener listener;
private TracksInfo lastSeenTrackGroupInfo; private Tracks lastSeenTracks;
private int currentItemIndex; private int currentItemIndex;
private Player currentPlayer; private Player currentPlayer;
@ -219,19 +219,19 @@ import java.util.ArrayList;
} }
@Override @Override
public void onTracksInfoChanged(TracksInfo tracksInfo) { public void onTracksChanged(Tracks tracks) {
if (currentPlayer != localPlayer || tracksInfo == lastSeenTrackGroupInfo) { if (currentPlayer != localPlayer || tracks == lastSeenTracks) {
return; return;
} }
if (tracksInfo.containsType(C.TRACK_TYPE_VIDEO) if (tracks.containsType(C.TRACK_TYPE_VIDEO)
&& !tracksInfo.isTypeSupported(C.TRACK_TYPE_VIDEO, /* allowExceedsCapabilities= */ true)) { && !tracks.isTypeSupported(C.TRACK_TYPE_VIDEO, /* allowExceedsCapabilities= */ true)) {
listener.onUnsupportedTrack(C.TRACK_TYPE_VIDEO); listener.onUnsupportedTrack(C.TRACK_TYPE_VIDEO);
} }
if (tracksInfo.containsType(C.TRACK_TYPE_AUDIO) if (tracks.containsType(C.TRACK_TYPE_AUDIO)
&& !tracksInfo.isTypeSupported(C.TRACK_TYPE_AUDIO, /* allowExceedsCapabilities= */ true)) { && !tracks.isTypeSupported(C.TRACK_TYPE_AUDIO, /* allowExceedsCapabilities= */ true)) {
listener.onUnsupportedTrack(C.TRACK_TYPE_AUDIO); listener.onUnsupportedTrack(C.TRACK_TYPE_AUDIO);
} }
lastSeenTrackGroupInfo = tracksInfo; lastSeenTracks = tracks;
} }
// CastPlayer.SessionAvailabilityListener implementation. // CastPlayer.SessionAvailabilityListener implementation.

View File

@ -28,7 +28,7 @@ import androidx.fragment.app.FragmentManager;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.MediaItem; import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.RenderersFactory; import com.google.android.exoplayer2.RenderersFactory;
import com.google.android.exoplayer2.TracksInfo; import com.google.android.exoplayer2.Tracks;
import com.google.android.exoplayer2.drm.DrmInitData; import com.google.android.exoplayer2.drm.DrmInitData;
import com.google.android.exoplayer2.drm.DrmSession; import com.google.android.exoplayer2.drm.DrmSession;
import com.google.android.exoplayer2.drm.DrmSessionEventListener; import com.google.android.exoplayer2.drm.DrmSessionEventListener;
@ -301,17 +301,17 @@ public class DownloadTracker {
return; return;
} }
TracksInfo tracksInfo = downloadHelper.getTracksInfo(/* periodIndex= */ 0); Tracks tracks = downloadHelper.getTracks(/* periodIndex= */ 0);
if (!TrackSelectionDialog.willHaveContent(tracksInfo)) { if (!TrackSelectionDialog.willHaveContent(tracks)) {
Log.d(TAG, "No dialog content. Downloading entire stream."); Log.d(TAG, "No dialog content. Downloading entire stream.");
startDownload(); startDownload();
downloadHelper.release(); downloadHelper.release();
return; return;
} }
trackSelectionDialog = trackSelectionDialog =
TrackSelectionDialog.createForTracksInfoAndParameters( TrackSelectionDialog.createForTracksAndParameters(
/* titleId= */ R.string.exo_download_description, /* titleId= */ R.string.exo_download_description,
tracksInfo, tracks,
DownloadHelper.getDefaultTrackSelectorParameters(context), DownloadHelper.getDefaultTrackSelectorParameters(context),
/* allowAdaptiveSelections= */ false, /* allowAdaptiveSelections= */ false,
/* allowMultipleOverrides= */ true, /* allowMultipleOverrides= */ true,

View File

@ -35,7 +35,7 @@ import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.PlaybackException; import com.google.android.exoplayer2.PlaybackException;
import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.RenderersFactory; import com.google.android.exoplayer2.RenderersFactory;
import com.google.android.exoplayer2.TracksInfo; import com.google.android.exoplayer2.Tracks;
import com.google.android.exoplayer2.audio.AudioAttributes; import com.google.android.exoplayer2.audio.AudioAttributes;
import com.google.android.exoplayer2.drm.FrameworkMediaDrm; import com.google.android.exoplayer2.drm.FrameworkMediaDrm;
import com.google.android.exoplayer2.ext.ima.ImaAdsLoader; import com.google.android.exoplayer2.ext.ima.ImaAdsLoader;
@ -82,7 +82,7 @@ public class PlayerActivity extends AppCompatActivity
private List<MediaItem> mediaItems; private List<MediaItem> mediaItems;
private TrackSelectionParameters trackSelectionParameters; private TrackSelectionParameters trackSelectionParameters;
private DebugTextViewHelper debugViewHelper; private DebugTextViewHelper debugViewHelper;
private TracksInfo lastSeenTracksInfo; private Tracks lastSeenTracks;
private boolean startAutoPlay; private boolean startAutoPlay;
private int startItemIndex; private int startItemIndex;
private long startPosition; private long startPosition;
@ -275,7 +275,7 @@ public class PlayerActivity extends AppCompatActivity
RenderersFactory renderersFactory = RenderersFactory renderersFactory =
DemoUtil.buildRenderersFactory(/* context= */ this, preferExtensionDecoders); DemoUtil.buildRenderersFactory(/* context= */ this, preferExtensionDecoders);
lastSeenTracksInfo = TracksInfo.EMPTY; lastSeenTracks = Tracks.EMPTY;
player = player =
new ExoPlayer.Builder(/* context= */ this) new ExoPlayer.Builder(/* context= */ this)
.setRenderersFactory(renderersFactory) .setRenderersFactory(renderersFactory)
@ -455,22 +455,20 @@ public class PlayerActivity extends AppCompatActivity
@Override @Override
@SuppressWarnings("ReferenceEquality") @SuppressWarnings("ReferenceEquality")
public void onTracksInfoChanged(TracksInfo tracksInfo) { public void onTracksChanged(Tracks tracks) {
updateButtonVisibility(); updateButtonVisibility();
if (tracksInfo == lastSeenTracksInfo) { if (tracks == lastSeenTracks) {
return; return;
} }
if (tracksInfo.containsType(C.TRACK_TYPE_VIDEO) if (tracks.containsType(C.TRACK_TYPE_VIDEO)
&& !tracksInfo.isTypeSupported( && !tracks.isTypeSupported(C.TRACK_TYPE_VIDEO, /* allowExceedsCapabilities= */ true)) {
C.TRACK_TYPE_VIDEO, /* allowExceedsCapabilities= */ true)) {
showToast(R.string.error_unsupported_video); showToast(R.string.error_unsupported_video);
} }
if (tracksInfo.containsType(C.TRACK_TYPE_AUDIO) if (tracks.containsType(C.TRACK_TYPE_AUDIO)
&& !tracksInfo.isTypeSupported( && !tracks.isTypeSupported(C.TRACK_TYPE_AUDIO, /* allowExceedsCapabilities= */ true)) {
C.TRACK_TYPE_AUDIO, /* allowExceedsCapabilities= */ true)) {
showToast(R.string.error_unsupported_audio); showToast(R.string.error_unsupported_audio);
} }
lastSeenTracksInfo = tracksInfo; lastSeenTracks = tracks;
} }
} }

View File

@ -33,8 +33,7 @@ import androidx.fragment.app.FragmentPagerAdapter;
import androidx.viewpager.widget.ViewPager; import androidx.viewpager.widget.ViewPager;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.TracksInfo; import com.google.android.exoplayer2.Tracks;
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.TrackSelectionOverride; import com.google.android.exoplayer2.trackselection.TrackSelectionOverride;
import com.google.android.exoplayer2.trackselection.TrackSelectionParameters; import com.google.android.exoplayer2.trackselection.TrackSelectionParameters;
@ -79,16 +78,16 @@ public final class TrackSelectionDialog extends DialogFragment {
* specified {@link Player}. * specified {@link Player}.
*/ */
public static boolean willHaveContent(Player player) { public static boolean willHaveContent(Player player) {
return willHaveContent(player.getCurrentTracksInfo()); return willHaveContent(player.getCurrentTracks());
} }
/** /**
* Returns whether a track selection dialog will have content to display if initialized with the * Returns whether a track selection dialog will have content to display if initialized with the
* specified {@link TracksInfo}. * specified {@link Tracks}.
*/ */
public static boolean willHaveContent(TracksInfo tracksInfo) { public static boolean willHaveContent(Tracks tracks) {
for (TrackGroupInfo trackGroupInfo : tracksInfo.getTrackGroupInfos()) { for (Tracks.Group trackGroup : tracks.getGroups()) {
if (SUPPORTED_TRACK_TYPES.contains(trackGroupInfo.getTrackType())) { if (SUPPORTED_TRACK_TYPES.contains(trackGroup.getType())) {
return true; return true;
} }
} }
@ -105,9 +104,9 @@ public final class TrackSelectionDialog extends DialogFragment {
*/ */
public static TrackSelectionDialog createForPlayer( public static TrackSelectionDialog createForPlayer(
Player player, DialogInterface.OnDismissListener onDismissListener) { Player player, DialogInterface.OnDismissListener onDismissListener) {
return createForTracksInfoAndParameters( return createForTracksAndParameters(
R.string.track_selection_title, R.string.track_selection_title,
player.getCurrentTracksInfo(), player.getCurrentTracks(),
player.getTrackSelectionParameters(), player.getTrackSelectionParameters(),
/* allowAdaptiveSelections= */ true, /* allowAdaptiveSelections= */ true,
/* allowMultipleOverrides= */ false, /* allowMultipleOverrides= */ false,
@ -116,10 +115,10 @@ public final class TrackSelectionDialog extends DialogFragment {
} }
/** /**
* Creates a dialog for given {@link TracksInfo} and {@link TrackSelectionParameters}. * Creates a dialog for given {@link Tracks} and {@link TrackSelectionParameters}.
* *
* @param titleId The resource id of the dialog title. * @param titleId The resource id of the dialog title.
* @param tracksInfo The {@link TracksInfo} describing the tracks to display. * @param tracks The {@link Tracks} describing the tracks to display.
* @param trackSelectionParameters The initial {@link TrackSelectionParameters}. * @param trackSelectionParameters The initial {@link TrackSelectionParameters}.
* @param allowAdaptiveSelections Whether adaptive selections (consisting of more than one track) * @param allowAdaptiveSelections Whether adaptive selections (consisting of more than one track)
* can be made. * can be made.
@ -128,9 +127,9 @@ public final class TrackSelectionDialog extends DialogFragment {
* @param onDismissListener {@link DialogInterface.OnDismissListener} called when the dialog is * @param onDismissListener {@link DialogInterface.OnDismissListener} called when the dialog is
* dismissed. * dismissed.
*/ */
public static TrackSelectionDialog createForTracksInfoAndParameters( public static TrackSelectionDialog createForTracksAndParameters(
int titleId, int titleId,
TracksInfo tracksInfo, Tracks tracks,
TrackSelectionParameters trackSelectionParameters, TrackSelectionParameters trackSelectionParameters,
boolean allowAdaptiveSelections, boolean allowAdaptiveSelections,
boolean allowMultipleOverrides, boolean allowMultipleOverrides,
@ -138,7 +137,7 @@ public final class TrackSelectionDialog extends DialogFragment {
DialogInterface.OnDismissListener onDismissListener) { DialogInterface.OnDismissListener onDismissListener) {
TrackSelectionDialog trackSelectionDialog = new TrackSelectionDialog(); TrackSelectionDialog trackSelectionDialog = new TrackSelectionDialog();
trackSelectionDialog.init( trackSelectionDialog.init(
tracksInfo, tracks,
trackSelectionParameters, trackSelectionParameters,
titleId, titleId,
allowAdaptiveSelections, allowAdaptiveSelections,
@ -169,7 +168,7 @@ public final class TrackSelectionDialog extends DialogFragment {
} }
private void init( private void init(
TracksInfo tracksInfo, Tracks tracks,
TrackSelectionParameters trackSelectionParameters, TrackSelectionParameters trackSelectionParameters,
int titleId, int titleId,
boolean allowAdaptiveSelections, boolean allowAdaptiveSelections,
@ -182,16 +181,16 @@ public final class TrackSelectionDialog extends DialogFragment {
for (int i = 0; i < SUPPORTED_TRACK_TYPES.size(); i++) { for (int i = 0; i < SUPPORTED_TRACK_TYPES.size(); i++) {
@C.TrackType int trackType = SUPPORTED_TRACK_TYPES.get(i); @C.TrackType int trackType = SUPPORTED_TRACK_TYPES.get(i);
ArrayList<TrackGroupInfo> trackGroupInfos = new ArrayList<>(); ArrayList<Tracks.Group> trackGroups = new ArrayList<>();
for (TrackGroupInfo trackGroupInfo : tracksInfo.getTrackGroupInfos()) { for (Tracks.Group trackGroup : tracks.getGroups()) {
if (trackGroupInfo.getTrackType() == trackType) { if (trackGroup.getType() == trackType) {
trackGroupInfos.add(trackGroupInfo); trackGroups.add(trackGroup);
} }
} }
if (!trackGroupInfos.isEmpty()) { if (!trackGroups.isEmpty()) {
TrackSelectionViewFragment tabFragment = new TrackSelectionViewFragment(); TrackSelectionViewFragment tabFragment = new TrackSelectionViewFragment();
tabFragment.init( tabFragment.init(
trackGroupInfos, trackGroups,
trackSelectionParameters.disabledTrackTypes.contains(trackType), trackSelectionParameters.disabledTrackTypes.contains(trackType),
trackSelectionParameters.overrides, trackSelectionParameters.overrides,
allowAdaptiveSelections, allowAdaptiveSelections,
@ -300,7 +299,7 @@ public final class TrackSelectionDialog extends DialogFragment {
public static final class TrackSelectionViewFragment extends Fragment public static final class TrackSelectionViewFragment extends Fragment
implements TrackSelectionView.TrackSelectionListener { implements TrackSelectionView.TrackSelectionListener {
private List<TrackGroupInfo> trackGroupInfos; private List<Tracks.Group> trackGroups;
private boolean allowAdaptiveSelections; private boolean allowAdaptiveSelections;
private boolean allowMultipleOverrides; private boolean allowMultipleOverrides;
@ -313,12 +312,12 @@ public final class TrackSelectionDialog extends DialogFragment {
} }
public void init( public void init(
List<TrackGroupInfo> trackGroupInfos, List<Tracks.Group> trackGroups,
boolean isDisabled, boolean isDisabled,
Map<TrackGroup, TrackSelectionOverride> overrides, Map<TrackGroup, TrackSelectionOverride> overrides,
boolean allowAdaptiveSelections, boolean allowAdaptiveSelections,
boolean allowMultipleOverrides) { boolean allowMultipleOverrides) {
this.trackGroupInfos = trackGroupInfos; this.trackGroups = trackGroups;
this.isDisabled = isDisabled; this.isDisabled = isDisabled;
this.allowAdaptiveSelections = allowAdaptiveSelections; this.allowAdaptiveSelections = allowAdaptiveSelections;
this.allowMultipleOverrides = allowMultipleOverrides; this.allowMultipleOverrides = allowMultipleOverrides;
@ -326,8 +325,7 @@ public final class TrackSelectionDialog extends DialogFragment {
// handle the case where the TrackSelectionView is never created. // handle the case where the TrackSelectionView is never created.
this.overrides = this.overrides =
new HashMap<>( new HashMap<>(
TrackSelectionView.filterOverrides( TrackSelectionView.filterOverrides(overrides, trackGroups, allowMultipleOverrides));
overrides, trackGroupInfos, allowMultipleOverrides));
} }
@Override @Override
@ -343,7 +341,7 @@ public final class TrackSelectionDialog extends DialogFragment {
trackSelectionView.setAllowMultipleOverrides(allowMultipleOverrides); trackSelectionView.setAllowMultipleOverrides(allowMultipleOverrides);
trackSelectionView.setAllowAdaptiveSelections(allowAdaptiveSelections); trackSelectionView.setAllowAdaptiveSelections(allowAdaptiveSelections);
trackSelectionView.init( trackSelectionView.init(
trackGroupInfos, trackGroups,
isDisabled, isDisabled,
overrides, overrides,
/* trackFormatComparator= */ null, /* trackFormatComparator= */ null,

View File

@ -2,49 +2,63 @@
title: Track selection title: Track selection
--- ---
Track selection determines which of the available media tracks are played by the When a media item contains multiple tracks, track selection is the process that
player. This process is configured by [`TrackSelectionParameters`][], which determines which of them are chosen for playback. The track selection process is
support many different options to specify constraints and overrides. configured by [`TrackSelectionParameters`][], which allows many different
constraints and overrides influencing track selection to be specified.
## Information about existing tracks ## Querying the available tracks
The player needs to prepare the media to know which tracks are available for You can listen to `Player.Listener.onTracksChanged` to be notified about changes
selection. You can listen to `Player.Listener.onTracksInfoChanged` to get to tracks, including:
notified about changes, which may happen
* When preparation completes * The available tracks becoming known when preparation of the media item being
* When the available or selected tracks change played completes. Note that the player needs to prepare a media item to know
* When the playlist item changes what tracks it contains.
* The available tracks changing due to playback transitioning from one media
item to another.
* Changes to the selected tracks.
~~~ ~~~
player.addListener(new Player.Listener() { player.addListener(new Player.Listener() {
@Override @Override
public void onTracksInfoChanged(TracksInfo tracksInfo) { public void onTracksChanged(Tracks tracks) {
// Update UI using current TracksInfo. // Update UI using current tracks.
} }
}); });
~~~ ~~~
{: .language-java} {: .language-java}
You can also retrieve the current `TracksInfo` by calling You can also query the current tracks by calling `player.getCurrentTracks()`.
`player.getCurrentTracksInfo()`. The returned `Tracks` contains a list of `Track.Group`s, where tracks within a
single `Group` present the same content but in different formats.
`TracksInfo` contains a list of `TrackGroupInfo`s with information about the As an example of how tracks can be grouped, consider an adaptive playback where
track type, format details, player support and selection status of each a main video feed is provided in five bitrates, and an alternative video feed
available track. Tracks are grouped together into one `TrackGroup` if they (e.g., a different camera angle in a sports match) is provided in two bitrates.
represent the same content that can be used interchangeably by the player (for In this case there will be two video track groups, one corresponding to the main
example, all audio tracks of a single language, but with different bitrates). video feed containing five tracks, and a second for the alternative video feed
containing two tracks.
Audio tracks whose languages differ are not grouped, because content in
different languages is not considered to be the same. Conversely, audio tracks
in the same language that only differ in properties such as bitrate, sampling
rate, channel count and so on can be grouped. This also applies to text tracks.
Each `Group` can be queried to determine which tracks are supported for
playback, which are currently selected, and what `Format` each track uses:
~~~ ~~~
for (TrackGroupInfo groupInfo : tracksInfo.getTrackGroupInfos()) { for (Tracks.Group trackGroup : tracks.getGroups()) {
// Group level information. // Group level information.
@C.TrackType int trackType = groupInfo.getTrackType(); @C.TrackType int trackType = trackGroup.getTrackType();
boolean trackInGroupIsSelected = groupInfo.isSelected(); boolean trackInGroupIsSelected = trackGroup.isSelected();
boolean trackInGroupIsSupported = groupInfo.isSupported(); boolean trackInGroupIsSupported = trackGroup.isSupported();
for (int i = 0; i < groupInfo.length; i++) { for (int i = 0; i < trackGroup.length; i++) {
// Individual track information. // Individual track information.
boolean isSupported = groupInfo.isTrackSupported(i); boolean isSupported = trackGroup.isTrackSupported(i);
boolean isSelected = groupInfo.isTrackSelected(i); boolean isSelected = trackGroup.isTrackSelected(i);
Format trackFormat = groupInfo.getTrackFormat(i); Format trackFormat = trackGroup.getTrackFormat(i);
} }
} }
~~~ ~~~
@ -55,22 +69,19 @@ for (TrackGroupInfo groupInfo : tracksInfo.getTrackGroupInfos()) {
multiple audio track groups) are supported, it only means that they are multiple audio track groups) are supported, it only means that they are
supported individually and the player is not necessarily able to play them at supported individually and the player is not necessarily able to play them at
the same time. the same time.
* A track is 'selected' if the track selector chose this track for playback * A track is 'selected' if it has been chosen for playback given the current
using the current `TrackSelectionParameters`. If multiple tracks within one `TrackSelectionParameters`. If multiple tracks within one track group are
track group are selected, the player uses these tracks for adaptive playback selected, the player uses these tracks for adaptive playback (for example,
(for example, multiple video tracks with different bitrates). Note that only multiple video tracks with different bitrates). Note that only one of these
one of these tracks will be played at any one time. If you want to be notified tracks will be played at any one time.
of in-playback changes to the adaptive video track you can listen to
`Player.Listener.onVideoSizeChanged`.
## Modifying track selection parameters ## Modifying track selection parameters
The selection process can be configured by setting `TrackSelectionParameters` on The track selection process can be configured using
the `Player` with `Player.setTrackSelectionParameters`. These updates can be `Player.setTrackSelectionParameters`. This can be done both before and during
done before and during playback. In most cases, it's advisable to obtain the playback. The example below demonstrates how to obtain the current
current parameters and only modify the required aspects with the `TrackSelectionParameters` from the player, modify them, and update the `Player`
`TrackSelectionParameters.Builder`. The builder class also allows chaining to with the modified result:
specify multiple options with one command:
~~~ ~~~
player.setTrackSelectionParameters( player.setTrackSelectionParameters(
@ -85,58 +96,60 @@ player.setTrackSelectionParameters(
### Constraint based track selection ### Constraint based track selection
Most options in `TrackSelectionParameters` allow you to specify constraints, Most options in `TrackSelectionParameters` allow you to specify constraints,
which are independent of the tracks that are actually available. Typical which are independent of the tracks that are actually available. Available
constraints are: constraints include:
* Maximum or minimum video width, height, frame rate, or bitrate. * Maximum and minimum video width, height, frame rate, and bitrate.
* Maximum audio channel count or bitrate. * Maximum audio channel count and bitrate.
* Preferred MIME types for video or audio. * Preferred MIME types for video and audio.
* Preferred audio languages or role flags. * Preferred audio languages and role flags.
* Preferred text languages or role flags. * Preferred text languages and role flags.
Note that ExoPlayer already applies sensible defaults for most of these values, ExoPlayer uses sensible defaults for these constraints, for example restricting
for example restricting video resolution to the display size or preferring the video resolution to the display size and preferring the audio language that
audio language that matches the user's system Locale setting. matches the user's system Locale setting.
There are several benefits to using constraint based track selection instead of There are several benefits to using constraint based track selection rather than
specifying specific tracks directly: selecting specific tracks from those that are available:
* You can specify constraints before knowing what tracks the media provides. * You can specify constraints before knowing what tracks a media item provides.
This allows to immediately select the appropriate tracks for faster startup This means that constraints can be specified before the player has prepared a
time and also simplifies track selection code as you don't have to listen for media item, whereas selecting specific tracks requires application code to
changes in the available tracks. wait until the available tracks become known.
* Constraints can be applied consistently across all items in a playlist. For * Constraints are applied for all media items in a playlist, even when those
example, selecting an audio language based on user preference will items have different available tracks. For example, a preferred audio language
automatically apply to the next playlist item too, whereas overriding a constraint will be automatically applied for all media items, even if the
specific track will only apply to the current playlist item for which the `Format` of the track in that language varies from one media item to the next.
track exists. This is not the case when selecting specific tracks, as described below.
### Selecting specific tracks ### Selecting specific tracks
It's possible to specify in `TrackSelectionParameters` which of the currently It's possible to select specific tracks using `TrackSelectionParameters`. First,
available tracks should be selected. First, the player's currently available the player's currently available tracks should be queried using
tracks should be queried using `Player.getTracksInfo`. Second, having identified `Player.getCurrentTracks`. Second, having identified which tracks to select,
which tracks to select, they can be set on `TrackSelectionParameters` using they can be set on `TrackSelectionParameters` using a `TrackSelectionOverride`.
`TrackSelectionOverrides`. For example, to select the first track from a For example, to select the first track from a specific `audioTrackGroup`:
specific `audioTrackGroup`:
~~~ ~~~
player.setTrackSelectionParameters( player.setTrackSelectionParameters(
player.getTrackSelectionParameters() player.getTrackSelectionParameters()
.buildUpon() .buildUpon()
.setOverrideForType( .setOverrideForType(
new TrackSelectionOverride(audioTrackGroup, /* trackIndex= */ 0)) new TrackSelectionOverride(
audioTrackGroup.getTrackGroup(),
/* trackIndex= */ 0))
.build()); .build());
~~~ ~~~
{: .language-java} {: .language-java}
Note that a `TrackSelectionOverride` will only apply to media items that contain A `TrackSelectionOverride` will only apply to media items that contain a
the `TrackGroup` specified in the override. Hence an override may not apply to `TrackGroup` exactly matching the one specified in the override. Hence an
a subsequent media item if that item contains different tracks. override may not apply to a subsequent media item if that item contains
different tracks.
### Disabling track types or groups ### Disabling track types or groups
Track types, like video, audio or text, can be disabled completely using Track types like video, audio or text, can be disabled completely using
`TrackSelectionParameters.Builder.setTrackTypeDisabled`. A disabled track type `TrackSelectionParameters.Builder.setTrackTypeDisabled`. A disabled track type
will be disabled for all media items: will be disabled for all media items:
@ -158,7 +171,7 @@ player.setTrackSelectionParameters(
.buildUpon() .buildUpon()
.addOverride( .addOverride(
new TrackSelectionOverride( new TrackSelectionOverride(
disabledTrackGroup, ImmutableList.of())) disabledTrackGroup.getTrackGroup(), ImmutableList.of()))
.build()); .build());
~~~ ~~~
{: .language-java} {: .language-java}

View File

@ -37,8 +37,7 @@ import com.google.android.exoplayer2.PlaybackException;
import com.google.android.exoplayer2.PlaybackParameters; import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.TracksInfo; import com.google.android.exoplayer2.Tracks;
import com.google.android.exoplayer2.TracksInfo.TrackGroupInfo;
import com.google.android.exoplayer2.audio.AudioAttributes; import com.google.android.exoplayer2.audio.AudioAttributes;
import com.google.android.exoplayer2.source.TrackGroup; import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.text.Cue; import com.google.android.exoplayer2.text.Cue;
@ -134,7 +133,7 @@ public final class CastPlayer extends BasePlayer {
private final StateHolder<PlaybackParameters> playbackParameters; private final StateHolder<PlaybackParameters> playbackParameters;
@Nullable private RemoteMediaClient remoteMediaClient; @Nullable private RemoteMediaClient remoteMediaClient;
private CastTimeline currentTimeline; private CastTimeline currentTimeline;
private TracksInfo currentTracksInfo; private Tracks currentTracks;
private Commands availableCommands; private Commands availableCommands;
private @Player.State int playbackState; private @Player.State int playbackState;
private int currentWindowIndex; private int currentWindowIndex;
@ -210,7 +209,7 @@ public final class CastPlayer extends BasePlayer {
playbackParameters = new StateHolder<>(PlaybackParameters.DEFAULT); playbackParameters = new StateHolder<>(PlaybackParameters.DEFAULT);
playbackState = STATE_IDLE; playbackState = STATE_IDLE;
currentTimeline = CastTimeline.EMPTY_CAST_TIMELINE; currentTimeline = CastTimeline.EMPTY_CAST_TIMELINE;
currentTracksInfo = TracksInfo.EMPTY; currentTracks = Tracks.EMPTY;
availableCommands = new Commands.Builder().addAll(PERMANENT_AVAILABLE_COMMANDS).build(); availableCommands = new Commands.Builder().addAll(PERMANENT_AVAILABLE_COMMANDS).build();
pendingSeekWindowIndex = C.INDEX_UNSET; pendingSeekWindowIndex = C.INDEX_UNSET;
pendingSeekPositionMs = C.TIME_UNSET; pendingSeekPositionMs = C.TIME_UNSET;
@ -542,8 +541,8 @@ public final class CastPlayer extends BasePlayer {
} }
@Override @Override
public TracksInfo getCurrentTracksInfo() { public Tracks getCurrentTracks() {
return currentTracksInfo; return currentTracks;
} }
@Override @Override
@ -816,7 +815,7 @@ public final class CastPlayer extends BasePlayer {
} }
if (updateTracksAndSelectionsAndNotifyIfChanged()) { if (updateTracksAndSelectionsAndNotifyIfChanged()) {
listeners.queueEvent( listeners.queueEvent(
Player.EVENT_TRACKS_CHANGED, listener -> listener.onTracksInfoChanged(currentTracksInfo)); Player.EVENT_TRACKS_CHANGED, listener -> listener.onTracksChanged(currentTracks));
} }
updateAvailableCommandsAndNotifyIfChanged(); updateAvailableCommandsAndNotifyIfChanged();
listeners.flushEvents(); listeners.flushEvents();
@ -976,8 +975,8 @@ public final class CastPlayer extends BasePlayer {
@Nullable @Nullable
List<MediaTrack> castMediaTracks = mediaInfo != null ? mediaInfo.getMediaTracks() : null; List<MediaTrack> castMediaTracks = mediaInfo != null ? mediaInfo.getMediaTracks() : null;
if (castMediaTracks == null || castMediaTracks.isEmpty()) { if (castMediaTracks == null || castMediaTracks.isEmpty()) {
boolean hasChanged = !TracksInfo.EMPTY.equals(currentTracksInfo); boolean hasChanged = !Tracks.EMPTY.equals(currentTracks);
currentTracksInfo = TracksInfo.EMPTY; currentTracks = Tracks.EMPTY;
return hasChanged; return hasChanged;
} }
@Nullable long[] activeTrackIds = mediaStatus.getActiveTrackIds(); @Nullable long[] activeTrackIds = mediaStatus.getActiveTrackIds();
@ -985,20 +984,19 @@ public final class CastPlayer extends BasePlayer {
activeTrackIds = EMPTY_TRACK_ID_ARRAY; activeTrackIds = EMPTY_TRACK_ID_ARRAY;
} }
TrackGroupInfo[] trackGroupInfos = new TrackGroupInfo[castMediaTracks.size()]; Tracks.Group[] trackGroups = new Tracks.Group[castMediaTracks.size()];
for (int i = 0; i < castMediaTracks.size(); i++) { for (int i = 0; i < castMediaTracks.size(); i++) {
MediaTrack mediaTrack = castMediaTracks.get(i); MediaTrack mediaTrack = castMediaTracks.get(i);
TrackGroup trackGroup = TrackGroup trackGroup =
new TrackGroup(/* id= */ Integer.toString(i), CastUtils.mediaTrackToFormat(mediaTrack)); new TrackGroup(/* id= */ Integer.toString(i), CastUtils.mediaTrackToFormat(mediaTrack));
@C.FormatSupport int[] trackSupport = new int[] {C.FORMAT_HANDLED}; @C.FormatSupport int[] trackSupport = new int[] {C.FORMAT_HANDLED};
boolean[] trackSelected = new boolean[] {isTrackActive(mediaTrack.getId(), activeTrackIds)}; boolean[] trackSelected = new boolean[] {isTrackActive(mediaTrack.getId(), activeTrackIds)};
trackGroupInfos[i] = trackGroups[i] =
new TrackGroupInfo( new Tracks.Group(trackGroup, /* adaptiveSupported= */ false, trackSupport, trackSelected);
trackGroup, /* adaptiveSupported= */ false, trackSupport, trackSelected);
} }
TracksInfo newTracksInfo = new TracksInfo(ImmutableList.copyOf(trackGroupInfos)); Tracks newTracks = new Tracks(ImmutableList.copyOf(trackGroups));
if (!newTracksInfo.equals(currentTracksInfo)) { if (!newTracks.equals(currentTracks)) {
currentTracksInfo = newTracksInfo; currentTracks = newTracks;
return true; return true;
} }
return false; return false;

View File

@ -710,7 +710,7 @@ import java.util.Map;
} }
// Check for a selected track using an audio renderer. // Check for a selected track using an audio renderer.
return player.getCurrentTracksInfo().isTypeSelected(C.TRACK_TYPE_AUDIO) ? 100 : 0; return player.getCurrentTracks().isTypeSelected(C.TRACK_TYPE_AUDIO) ? 100 : 0;
} }
private void handleAdEvent(AdEvent adEvent) { private void handleAdEvent(AdEvent adEvent) {

View File

@ -24,7 +24,7 @@ import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.PlaybackException; import com.google.android.exoplayer2.PlaybackException;
import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.TracksInfo; import com.google.android.exoplayer2.Tracks;
import com.google.android.exoplayer2.testutil.StubExoPlayer; import com.google.android.exoplayer2.testutil.StubExoPlayer;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import com.google.android.exoplayer2.trackselection.TrackSelectionParameters; import com.google.android.exoplayer2.trackselection.TrackSelectionParameters;
@ -266,8 +266,8 @@ import com.google.android.exoplayer2.util.Util;
} }
@Override @Override
public TracksInfo getCurrentTracksInfo() { public Tracks getCurrentTracks() {
return TracksInfo.EMPTY; return Tracks.EMPTY;
} }
@Override @Override

View File

@ -444,10 +444,10 @@ public class ForwardingPlayer implements Player {
player.release(); player.release();
} }
/** Calls {@link Player#getCurrentTracksInfo()} on the delegate and returns the result. */ /** Calls {@link Player#getCurrentTracks()} on the delegate and returns the result. */
@Override @Override
public TracksInfo getCurrentTracksInfo() { public Tracks getCurrentTracks() {
return player.getCurrentTracksInfo(); return player.getCurrentTracks();
} }
/** Calls {@link Player#getTrackSelectionParameters()} on the delegate and returns the result. */ /** Calls {@link Player#getTrackSelectionParameters()} on the delegate and returns the result. */
@ -833,8 +833,8 @@ public class ForwardingPlayer implements Player {
} }
@Override @Override
public void onTracksInfoChanged(TracksInfo tracksInfo) { public void onTracksChanged(Tracks tracks) {
listener.onTracksInfoChanged(tracksInfo); listener.onTracksChanged(tracks);
} }
@Override @Override

View File

@ -61,8 +61,8 @@ import java.util.List;
* <ul> * <ul>
* <li>They can provide a {@link Timeline} representing the structure of the media being played, * <li>They can provide a {@link Timeline} representing the structure of the media being played,
* which can be obtained by calling {@link #getCurrentTimeline()}. * which can be obtained by calling {@link #getCurrentTimeline()}.
* <li>They can provide a {@link TracksInfo} defining the currently available tracks and which are * <li>They can provide a {@link Tracks} defining the currently available tracks and which are
* selected to be rendered, which can be obtained by calling {@link #getCurrentTracksInfo()}. * selected to be rendered, which can be obtained by calling {@link #getCurrentTracks()}.
* </ul> * </ul>
*/ */
public interface Player { public interface Player {
@ -673,14 +673,14 @@ public interface Player {
@Nullable MediaItem mediaItem, @MediaItemTransitionReason int reason) {} @Nullable MediaItem mediaItem, @MediaItemTransitionReason int reason) {}
/** /**
* Called when the available or selected tracks change. * Called when the tracks change.
* *
* <p>{@link #onEvents(Player, Events)} will also be called to report this event along with * <p>{@link #onEvents(Player, Events)} will also be called to report this event along with
* other events that happen in the same {@link Looper} message queue iteration. * other events that happen in the same {@link Looper} message queue iteration.
* *
* @param tracksInfo The available tracks information. Never null, but may be of length zero. * @param tracks The available tracks information. Never null, but may be of length zero.
*/ */
default void onTracksInfoChanged(TracksInfo tracksInfo) {} default void onTracksChanged(Tracks tracks) {}
/** /**
* Called when the combined {@link MediaMetadata} changes. * Called when the combined {@link MediaMetadata} changes.
@ -1299,7 +1299,7 @@ public interface Player {
int EVENT_TIMELINE_CHANGED = 0; int EVENT_TIMELINE_CHANGED = 0;
/** {@link #getCurrentMediaItem()} changed or the player started repeating the current item. */ /** {@link #getCurrentMediaItem()} changed or the player started repeating the current item. */
int EVENT_MEDIA_ITEM_TRANSITION = 1; int EVENT_MEDIA_ITEM_TRANSITION = 1;
/** {@link #getCurrentTracksInfo()} changed. */ /** {@link #getCurrentTracks()} changed. */
int EVENT_TRACKS_CHANGED = 2; int EVENT_TRACKS_CHANGED = 2;
/** {@link #isLoading()} ()} changed. */ /** {@link #isLoading()} ()} changed. */
int EVENT_IS_LOADING_CHANGED = 3; int EVENT_IS_LOADING_CHANGED = 3;
@ -2074,11 +2074,11 @@ public interface Player {
void release(); void release();
/** /**
* Returns information about the current tracks. * Returns the current tracks.
* *
* @see Listener#onTracksInfoChanged(TracksInfo) * @see Listener#onTracksChanged(Tracks)
*/ */
TracksInfo getCurrentTracksInfo(); Tracks getCurrentTracks();
/** /**
* Returns the parameters constraining the track selection. * Returns the parameters constraining the track selection.

View File

@ -37,14 +37,14 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
/** Information about groups of tracks. */ /** Information about groups of tracks. */
public final class TracksInfo implements Bundleable { public final class Tracks implements Bundleable {
/** /**
* Information about a single group of tracks, including the underlying {@link TrackGroup}, the * Information about a single group of tracks, including the underlying {@link TrackGroup}, the
* level to which each track is supported by the player, and whether any of the tracks are * level to which each track is supported by the player, and whether any of the tracks are
* selected. * selected.
*/ */
public static final class TrackGroupInfo implements Bundleable { public static final class Group implements Bundleable {
/** The number of tracks in the group. */ /** The number of tracks in the group. */
public final int length; public final int length;
@ -63,7 +63,7 @@ public final class TracksInfo implements Bundleable {
* @param trackSupport The {@link C.FormatSupport} of each track in the group. * @param trackSupport The {@link C.FormatSupport} of each track in the group.
* @param trackSelected Whether each track in the {@code trackGroup} is selected. * @param trackSelected Whether each track in the {@code trackGroup} is selected.
*/ */
public TrackGroupInfo( public Group(
TrackGroup trackGroup, TrackGroup trackGroup,
boolean adaptiveSupported, boolean adaptiveSupported,
@C.FormatSupport int[] trackSupport, @C.FormatSupport int[] trackSupport,
@ -84,7 +84,7 @@ public final class TracksInfo implements Bundleable {
/** /**
* Returns the {@link Format} for a specified track. * Returns the {@link Format} for a specified track.
* *
* @param trackIndex The index of the track in the {@link TrackGroup}. * @param trackIndex The index of the track in the group.
* @return The {@link Format} of the track. * @return The {@link Format} of the track.
*/ */
public Format getTrackFormat(int trackIndex) { public Format getTrackFormat(int trackIndex) {
@ -94,7 +94,7 @@ public final class TracksInfo implements Bundleable {
/** /**
* Returns the level of support for a specified track. * Returns the level of support for a specified track.
* *
* @param trackIndex The index of the track in the {@link TrackGroup}. * @param trackIndex The index of the track in the group.
* @return The {@link C.FormatSupport} of the track. * @return The {@link C.FormatSupport} of the track.
*/ */
public @C.FormatSupport int getTrackSupport(int trackIndex) { public @C.FormatSupport int getTrackSupport(int trackIndex) {
@ -105,7 +105,7 @@ public final class TracksInfo implements Bundleable {
* Returns whether a specified track is supported for playback, without exceeding the advertised * Returns whether a specified track is supported for playback, without exceeding the advertised
* capabilities of the device. Equivalent to {@code isTrackSupported(trackIndex, false)}. * capabilities of the device. Equivalent to {@code isTrackSupported(trackIndex, false)}.
* *
* @param trackIndex The index of the track in the {@link TrackGroup}. * @param trackIndex The index of the track in the group.
* @return True if the track's format can be played, false otherwise. * @return True if the track's format can be played, false otherwise.
*/ */
public boolean isTrackSupported(int trackIndex) { public boolean isTrackSupported(int trackIndex) {
@ -115,7 +115,7 @@ public final class TracksInfo implements Bundleable {
/** /**
* Returns whether a specified track is supported for playback. * Returns whether a specified track is supported for playback.
* *
* @param trackIndex The index of the track in the {@link TrackGroup}. * @param trackIndex The index of the track in the group.
* @param allowExceedsCapabilities Whether to consider the track as supported if it has a * @param allowExceedsCapabilities Whether to consider the track as supported if it has a
* supported {@link Format#sampleMimeType MIME type}, but otherwise exceeds the advertised * supported {@link Format#sampleMimeType MIME type}, but otherwise exceeds the advertised
* capabilities of the device. For example, a video track for which there's a corresponding * capabilities of the device. For example, a video track for which there's a corresponding
@ -176,7 +176,7 @@ public final class TracksInfo implements Bundleable {
* playing, however some player implementations have ways of getting such information. For * playing, however some player implementations have ways of getting such information. For
* example, ExoPlayer provides this information via {@code ExoTrackSelection.getSelectedFormat}. * example, ExoPlayer provides this information via {@code ExoTrackSelection.getSelectedFormat}.
* *
* @param trackIndex The index of the track in the {@link TrackGroup}. * @param trackIndex The index of the track in the group.
* @return True if the track is selected, false otherwise. * @return True if the track is selected, false otherwise.
*/ */
public boolean isTrackSelected(int trackIndex) { public boolean isTrackSelected(int trackIndex) {
@ -184,7 +184,7 @@ public final class TracksInfo implements Bundleable {
} }
/** Returns the {@link C.TrackType} of the group. */ /** Returns the {@link C.TrackType} of the group. */
public @C.TrackType int getTrackType() { public @C.TrackType int getType() {
return trackGroup.type; return trackGroup.type;
} }
@ -196,7 +196,7 @@ public final class TracksInfo implements Bundleable {
if (other == null || getClass() != other.getClass()) { if (other == null || getClass() != other.getClass()) {
return false; return false;
} }
TrackGroupInfo that = (TrackGroupInfo) other; Group that = (Group) other;
return adaptiveSupported == that.adaptiveSupported return adaptiveSupported == that.adaptiveSupported
&& trackGroup.equals(that.trackGroup) && trackGroup.equals(that.trackGroup)
&& Arrays.equals(trackSupport, that.trackSupport) && Arrays.equals(trackSupport, that.trackSupport)
@ -239,8 +239,8 @@ public final class TracksInfo implements Bundleable {
return bundle; return bundle;
} }
/** Object that can restores a {@code TracksInfo} from a {@link Bundle}. */ /** Object that can restore a group of tracks from a {@link Bundle}. */
public static final Creator<TrackGroupInfo> CREATOR = public static final Creator<Group> CREATOR =
bundle -> { bundle -> {
TrackGroup trackGroup = TrackGroup trackGroup =
fromNullableBundle( fromNullableBundle(
@ -255,7 +255,7 @@ public final class TracksInfo implements Bundleable {
new boolean[trackGroup.length]); new boolean[trackGroup.length]);
boolean adaptiveSupported = boolean adaptiveSupported =
bundle.getBoolean(keyForField(FIELD_ADAPTIVE_SUPPORTED), false); bundle.getBoolean(keyForField(FIELD_ADAPTIVE_SUPPORTED), false);
return new TrackGroupInfo(trackGroup, adaptiveSupported, trackSupport, selected); return new Group(trackGroup, adaptiveSupported, trackSupport, selected);
}; };
private static String keyForField(@FieldNumber int field) { private static String keyForField(@FieldNumber int field) {
@ -263,30 +263,34 @@ public final class TracksInfo implements Bundleable {
} }
} }
/** An {@code TrackInfo} that contains no tracks. */ /** Empty tracks. */
public static final TracksInfo EMPTY = new TracksInfo(ImmutableList.of()); public static final Tracks EMPTY = new Tracks(ImmutableList.of());
private final ImmutableList<TrackGroupInfo> trackGroupInfos; private final ImmutableList<Group> groups;
/** /**
* Constructs an instance. * Constructs an instance.
* *
* @param trackGroupInfos The {@link TrackGroupInfo TrackGroupInfos} describing the groups of * @param groups The {@link Group groups} of tracks.
* tracks.
*/ */
public TracksInfo(List<TrackGroupInfo> trackGroupInfos) { public Tracks(List<Group> groups) {
this.trackGroupInfos = ImmutableList.copyOf(trackGroupInfos); this.groups = ImmutableList.copyOf(groups);
} }
/** Returns the {@link TrackGroupInfo TrackGroupInfos} describing the groups of tracks. */ /** Returns the {@link Group groups} of tracks. */
public ImmutableList<TrackGroupInfo> getTrackGroupInfos() { public ImmutableList<Group> getGroups() {
return trackGroupInfos; return groups;
}
/** Returns {@code true} if there are no tracks, and {@code false} otherwise. */
public boolean isEmpty() {
return groups.isEmpty();
} }
/** Returns true if there are tracks of type {@code trackType}, and false otherwise. */ /** Returns true if there are tracks of type {@code trackType}, and false otherwise. */
public boolean containsType(@C.TrackType int trackType) { public boolean containsType(@C.TrackType int trackType) {
for (int i = 0; i < trackGroupInfos.size(); i++) { for (int i = 0; i < groups.size(); i++) {
if (trackGroupInfos.get(i).getTrackType() == trackType) { if (groups.get(i).getType() == trackType) {
return true; return true;
} }
} }
@ -295,7 +299,7 @@ public final class TracksInfo implements Bundleable {
/** /**
* Returns true if at least one track of type {@code trackType} is {@link * Returns true if at least one track of type {@code trackType} is {@link
* TrackGroupInfo#isTrackSupported(int) supported}. * Group#isTrackSupported(int) supported}.
*/ */
public boolean isTypeSupported(@C.TrackType int trackType) { public boolean isTypeSupported(@C.TrackType int trackType) {
return isTypeSupported(trackType, /* allowExceedsCapabilities= */ false); return isTypeSupported(trackType, /* allowExceedsCapabilities= */ false);
@ -303,7 +307,7 @@ public final class TracksInfo implements Bundleable {
/** /**
* Returns true if at least one track of type {@code trackType} is {@link * Returns true if at least one track of type {@code trackType} is {@link
* TrackGroupInfo#isTrackSupported(int, boolean) supported}. * Group#isTrackSupported(int, boolean) supported}.
* *
* @param allowExceedsCapabilities Whether to consider the track as supported if it has a * @param allowExceedsCapabilities Whether to consider the track as supported if it has a
* supported {@link Format#sampleMimeType MIME type}, but otherwise exceeds the advertised * supported {@link Format#sampleMimeType MIME type}, but otherwise exceeds the advertised
@ -312,9 +316,9 @@ public final class TracksInfo implements Bundleable {
* Such tracks may be playable in some cases. * Such tracks may be playable in some cases.
*/ */
public boolean isTypeSupported(@C.TrackType int trackType, boolean allowExceedsCapabilities) { public boolean isTypeSupported(@C.TrackType int trackType, boolean allowExceedsCapabilities) {
for (int i = 0; i < trackGroupInfos.size(); i++) { for (int i = 0; i < groups.size(); i++) {
if (trackGroupInfos.get(i).getTrackType() == trackType) { if (groups.get(i).getType() == trackType) {
if (trackGroupInfos.get(i).isSupported(allowExceedsCapabilities)) { if (groups.get(i).isSupported(allowExceedsCapabilities)) {
return true; return true;
} }
} }
@ -342,9 +346,9 @@ public final class TracksInfo implements Bundleable {
/** Returns true if at least one track of the type {@code trackType} is selected for playback. */ /** Returns true if at least one track of the type {@code trackType} is selected for playback. */
public boolean isTypeSelected(@C.TrackType int trackType) { public boolean isTypeSelected(@C.TrackType int trackType) {
for (int i = 0; i < trackGroupInfos.size(); i++) { for (int i = 0; i < groups.size(); i++) {
TrackGroupInfo trackGroupInfo = trackGroupInfos.get(i); Group group = groups.get(i);
if (trackGroupInfo.isSelected() && trackGroupInfo.getTrackType() == trackType) { if (group.isSelected() && group.getType() == trackType) {
return true; return true;
} }
} }
@ -359,13 +363,13 @@ public final class TracksInfo implements Bundleable {
if (other == null || getClass() != other.getClass()) { if (other == null || getClass() != other.getClass()) {
return false; return false;
} }
TracksInfo that = (TracksInfo) other; Tracks that = (Tracks) other;
return trackGroupInfos.equals(that.trackGroupInfos); return groups.equals(that.groups);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return trackGroupInfos.hashCode(); return groups.hashCode();
} }
// Bundleable implementation. // Bundleable implementation.
@ -373,29 +377,28 @@ public final class TracksInfo implements Bundleable {
@Retention(RetentionPolicy.SOURCE) @Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE) @Target(TYPE_USE)
@IntDef({ @IntDef({
FIELD_TRACK_GROUP_INFOS, FIELD_TRACK_GROUPS,
}) })
private @interface FieldNumber {} private @interface FieldNumber {}
private static final int FIELD_TRACK_GROUP_INFOS = 0; private static final int FIELD_TRACK_GROUPS = 0;
@Override @Override
public Bundle toBundle() { public Bundle toBundle() {
Bundle bundle = new Bundle(); Bundle bundle = new Bundle();
bundle.putParcelableArrayList( bundle.putParcelableArrayList(keyForField(FIELD_TRACK_GROUPS), toBundleArrayList(groups));
keyForField(FIELD_TRACK_GROUP_INFOS), toBundleArrayList(trackGroupInfos));
return bundle; return bundle;
} }
/** Object that can restore a {@code TracksInfo} from a {@link Bundle}. */ /** Object that can restore tracks from a {@link Bundle}. */
public static final Creator<TracksInfo> CREATOR = public static final Creator<Tracks> CREATOR =
bundle -> { bundle -> {
List<TrackGroupInfo> trackGroupInfos = List<Group> groups =
fromBundleNullableList( fromBundleNullableList(
TrackGroupInfo.CREATOR, Group.CREATOR,
bundle.getParcelableArrayList(keyForField(FIELD_TRACK_GROUP_INFOS)), bundle.getParcelableArrayList(keyForField(FIELD_TRACK_GROUPS)),
/* defaultValue= */ ImmutableList.of()); /* defaultValue= */ ImmutableList.of());
return new TracksInfo(trackGroupInfos); return new Tracks(groups);
}; };
private static String keyForField(@FieldNumber int field) { private static String keyForField(@FieldNumber int field) {

View File

@ -94,7 +94,7 @@ public final class TrackSelectionOverride implements Bundleable {
} }
/** Returns the {@link C.TrackType} of the overridden track group. */ /** Returns the {@link C.TrackType} of the overridden track group. */
public @C.TrackType int getTrackType() { public @C.TrackType int getType() {
return trackGroup.type; return trackGroup.type;
} }

View File

@ -682,7 +682,7 @@ public class TrackSelectionParameters implements Bundleable {
/** Sets an override, replacing all existing overrides with the same track type. */ /** Sets an override, replacing all existing overrides with the same track type. */
public Builder setOverrideForType(TrackSelectionOverride override) { public Builder setOverrideForType(TrackSelectionOverride override) {
clearOverridesOfType(override.getTrackType()); clearOverridesOfType(override.getType());
overrides.put(override.trackGroup, override); overrides.put(override.trackGroup, override);
return this; return this;
} }
@ -698,7 +698,7 @@ public class TrackSelectionParameters implements Bundleable {
Iterator<TrackSelectionOverride> it = overrides.values().iterator(); Iterator<TrackSelectionOverride> it = overrides.values().iterator();
while (it.hasNext()) { while (it.hasNext()) {
TrackSelectionOverride override = it.next(); TrackSelectionOverride override = it.next();
if (override.getTrackType() == trackType) { if (override.getType() == trackType) {
it.remove(); it.remove();
} }
} }

View File

@ -1,145 +0,0 @@
/*
* 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;
import static com.google.android.exoplayer2.util.MimeTypes.AUDIO_AAC;
import static com.google.android.exoplayer2.util.MimeTypes.VIDEO_H264;
import static com.google.common.truth.Truth.assertThat;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.TracksInfo.TrackGroupInfo;
import com.google.android.exoplayer2.source.TrackGroup;
import com.google.common.collect.ImmutableList;
import org.junit.Test;
import org.junit.runner.RunWith;
/** Unit test for {@link TracksInfo}. */
@RunWith(AndroidJUnit4.class)
public class TracksInfoTest {
@Test
public void roundTripViaBundle_ofEmptyTracksInfo_yieldsEqualInstance() {
TracksInfo before = TracksInfo.EMPTY;
TracksInfo after = TracksInfo.CREATOR.fromBundle(before.toBundle());
assertThat(after).isEqualTo(before);
}
@Test
public void roundTripViaBundle_ofTracksInfo_yieldsEqualInstance() {
TracksInfo before =
new TracksInfo(
ImmutableList.of(
new TrackGroupInfo(
new TrackGroup(new Format.Builder().setSampleMimeType(AUDIO_AAC).build()),
/* adaptiveSupported= */ false,
new int[] {C.FORMAT_EXCEEDS_CAPABILITIES},
/* tracksSelected= */ new boolean[] {true}),
new TrackGroupInfo(
new TrackGroup(
new Format.Builder().setSampleMimeType(VIDEO_H264).build(),
new Format.Builder().setSampleMimeType(VIDEO_H264).build()),
/* adaptiveSupported= */ true,
new int[] {C.FORMAT_UNSUPPORTED_DRM, C.FORMAT_UNSUPPORTED_TYPE},
/* tracksSelected= */ new boolean[] {false, true})));
TracksInfo after = TracksInfo.CREATOR.fromBundle(before.toBundle());
assertThat(after).isEqualTo(before);
}
@Test
public void tracksInfoGetters_withoutTrack_returnExpectedValues() {
TracksInfo tracksInfo = new TracksInfo(ImmutableList.of());
assertThat(tracksInfo.containsType(C.TRACK_TYPE_AUDIO)).isFalse();
assertThat(tracksInfo.isTypeSupported(C.TRACK_TYPE_AUDIO)).isFalse();
assertThat(tracksInfo.isTypeSupported(C.TRACK_TYPE_AUDIO, /* allowExceedsCapabilities= */ true))
.isFalse();
assertThat(tracksInfo.isTypeSelected(C.TRACK_TYPE_AUDIO)).isFalse();
ImmutableList<TrackGroupInfo> trackGroupInfos = tracksInfo.getTrackGroupInfos();
assertThat(trackGroupInfos).isEmpty();
}
@Test
public void tracksInfo_emptyStaticInstance_isEmpty() {
TracksInfo tracksInfo = TracksInfo.EMPTY;
assertThat(tracksInfo.getTrackGroupInfos()).isEmpty();
assertThat(tracksInfo).isEqualTo(new TracksInfo(ImmutableList.of()));
}
@Test
public void tracksInfoGetters_ofComplexTracksInfo_returnExpectedValues() {
TrackGroupInfo trackGroupInfo0 =
new TrackGroupInfo(
new TrackGroup(new Format.Builder().setSampleMimeType(AUDIO_AAC).build()),
/* adaptiveSupported= */ false,
new int[] {C.FORMAT_EXCEEDS_CAPABILITIES},
/* tracksSelected= */ new boolean[] {false});
TrackGroupInfo trackGroupInfo1 =
new TrackGroupInfo(
new TrackGroup(
new Format.Builder().setSampleMimeType(VIDEO_H264).build(),
new Format.Builder().setSampleMimeType(VIDEO_H264).build()),
/* adaptiveSupported= */ true,
new int[] {C.FORMAT_UNSUPPORTED_DRM, C.FORMAT_HANDLED},
/* tracksSelected= */ new boolean[] {false, true});
TracksInfo tracksInfo = new TracksInfo(ImmutableList.of(trackGroupInfo0, trackGroupInfo1));
assertThat(tracksInfo.containsType(C.TRACK_TYPE_AUDIO)).isTrue();
assertThat(tracksInfo.containsType(C.TRACK_TYPE_VIDEO)).isTrue();
assertThat(tracksInfo.containsType(C.TRACK_TYPE_TEXT)).isFalse();
assertThat(tracksInfo.isTypeSupported(C.TRACK_TYPE_AUDIO)).isFalse();
assertThat(tracksInfo.isTypeSupported(C.TRACK_TYPE_VIDEO)).isTrue();
assertThat(tracksInfo.isTypeSupported(C.TRACK_TYPE_TEXT)).isFalse();
assertThat(tracksInfo.isTypeSupported(C.TRACK_TYPE_AUDIO, /* allowExceedsCapabilities= */ true))
.isTrue();
assertThat(tracksInfo.isTypeSupported(C.TRACK_TYPE_VIDEO, /* allowExceedsCapabilities= */ true))
.isTrue();
assertThat(tracksInfo.isTypeSupported(C.TRACK_TYPE_TEXT, /* allowExceedsCapabilities= */ true))
.isFalse();
assertThat(tracksInfo.isTypeSelected(C.TRACK_TYPE_AUDIO)).isFalse();
assertThat(tracksInfo.isTypeSelected(C.TRACK_TYPE_VIDEO)).isTrue();
ImmutableList<TrackGroupInfo> trackGroupInfos = tracksInfo.getTrackGroupInfos();
assertThat(trackGroupInfos).hasSize(2);
assertThat(trackGroupInfos.get(0)).isSameInstanceAs(trackGroupInfo0);
assertThat(trackGroupInfos.get(1)).isSameInstanceAs(trackGroupInfo1);
assertThat(trackGroupInfos.get(0).isTrackSupported(0)).isFalse();
assertThat(trackGroupInfos.get(1).isTrackSupported(0)).isFalse();
assertThat(trackGroupInfos.get(1).isTrackSupported(1)).isTrue();
assertThat(trackGroupInfos.get(0).getTrackSupport(0)).isEqualTo(C.FORMAT_EXCEEDS_CAPABILITIES);
assertThat(trackGroupInfos.get(1).getTrackSupport(0)).isEqualTo(C.FORMAT_UNSUPPORTED_DRM);
assertThat(trackGroupInfos.get(1).getTrackSupport(1)).isEqualTo(C.FORMAT_HANDLED);
assertThat(trackGroupInfos.get(0).isTrackSelected(0)).isFalse();
assertThat(trackGroupInfos.get(1).isTrackSelected(0)).isFalse();
assertThat(trackGroupInfos.get(1).isTrackSelected(1)).isTrue();
assertThat(trackGroupInfos.get(0).getTrackType()).isEqualTo(C.TRACK_TYPE_AUDIO);
assertThat(trackGroupInfos.get(1).getTrackType()).isEqualTo(C.TRACK_TYPE_VIDEO);
}
/**
* Tests that {@link TrackGroupInfo#isAdaptiveSupported} returns false if the group only contains
* a single track, even if true is passed to the constructor.
*/
@Test
public void trackGroupInfo_withSingleTrack_isNotAdaptive() {
TrackGroupInfo trackGroupInfo0 =
new TrackGroupInfo(
new TrackGroup(new Format.Builder().setSampleMimeType(AUDIO_AAC).build()),
/* adaptiveSupported= */ true,
new int[] {C.FORMAT_EXCEEDS_CAPABILITIES},
/* tracksSelected= */ new boolean[] {false});
assertThat(trackGroupInfo0.isAdaptiveSupported()).isFalse();
}
}

View File

@ -0,0 +1,144 @@
/*
* 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;
import static com.google.android.exoplayer2.util.MimeTypes.AUDIO_AAC;
import static com.google.android.exoplayer2.util.MimeTypes.VIDEO_H264;
import static com.google.common.truth.Truth.assertThat;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.source.TrackGroup;
import com.google.common.collect.ImmutableList;
import org.junit.Test;
import org.junit.runner.RunWith;
/** Unit test for {@link Tracks}. */
@RunWith(AndroidJUnit4.class)
public class TracksTest {
@Test
public void roundTripViaBundle_ofEmptyTracks_yieldsEqualInstance() {
Tracks before = Tracks.EMPTY;
Tracks after = Tracks.CREATOR.fromBundle(before.toBundle());
assertThat(after).isEqualTo(before);
}
@Test
public void roundTripViaBundle_ofTracks_yieldsEqualInstance() {
Tracks before =
new Tracks(
ImmutableList.of(
new Tracks.Group(
new TrackGroup(new Format.Builder().setSampleMimeType(AUDIO_AAC).build()),
/* adaptiveSupported= */ false,
new int[] {C.FORMAT_EXCEEDS_CAPABILITIES},
/* trackSelected= */ new boolean[] {true}),
new Tracks.Group(
new TrackGroup(
new Format.Builder().setSampleMimeType(VIDEO_H264).build(),
new Format.Builder().setSampleMimeType(VIDEO_H264).build()),
/* adaptiveSupported= */ true,
new int[] {C.FORMAT_UNSUPPORTED_DRM, C.FORMAT_UNSUPPORTED_TYPE},
/* trackSelected= */ new boolean[] {false, true})));
Tracks after = Tracks.CREATOR.fromBundle(before.toBundle());
assertThat(after).isEqualTo(before);
}
@Test
public void getters_withoutTrack_returnExpectedValues() {
Tracks tracks = new Tracks(ImmutableList.of());
assertThat(tracks.containsType(C.TRACK_TYPE_AUDIO)).isFalse();
assertThat(tracks.isTypeSupported(C.TRACK_TYPE_AUDIO)).isFalse();
assertThat(tracks.isTypeSupported(C.TRACK_TYPE_AUDIO, /* allowExceedsCapabilities= */ true))
.isFalse();
assertThat(tracks.isTypeSelected(C.TRACK_TYPE_AUDIO)).isFalse();
ImmutableList<Tracks.Group> trackGroups = tracks.getGroups();
assertThat(trackGroups).isEmpty();
}
@Test
public void emptyStaticInstance_isEmpty() {
Tracks tracks = Tracks.EMPTY;
assertThat(tracks.getGroups()).isEmpty();
assertThat(tracks).isEqualTo(new Tracks(ImmutableList.of()));
}
@Test
public void getters_ofComplexTracks_returnExpectedValues() {
Tracks.Group trackGroup0 =
new Tracks.Group(
new TrackGroup(new Format.Builder().setSampleMimeType(AUDIO_AAC).build()),
/* adaptiveSupported= */ false,
new int[] {C.FORMAT_EXCEEDS_CAPABILITIES},
/* trackSelected= */ new boolean[] {false});
Tracks.Group trackGroup1 =
new Tracks.Group(
new TrackGroup(
new Format.Builder().setSampleMimeType(VIDEO_H264).build(),
new Format.Builder().setSampleMimeType(VIDEO_H264).build()),
/* adaptiveSupported= */ true,
new int[] {C.FORMAT_UNSUPPORTED_DRM, C.FORMAT_HANDLED},
/* trackSelected= */ new boolean[] {false, true});
Tracks tracks = new Tracks(ImmutableList.of(trackGroup0, trackGroup1));
assertThat(tracks.containsType(C.TRACK_TYPE_AUDIO)).isTrue();
assertThat(tracks.containsType(C.TRACK_TYPE_VIDEO)).isTrue();
assertThat(tracks.containsType(C.TRACK_TYPE_TEXT)).isFalse();
assertThat(tracks.isTypeSupported(C.TRACK_TYPE_AUDIO)).isFalse();
assertThat(tracks.isTypeSupported(C.TRACK_TYPE_VIDEO)).isTrue();
assertThat(tracks.isTypeSupported(C.TRACK_TYPE_TEXT)).isFalse();
assertThat(tracks.isTypeSupported(C.TRACK_TYPE_AUDIO, /* allowExceedsCapabilities= */ true))
.isTrue();
assertThat(tracks.isTypeSupported(C.TRACK_TYPE_VIDEO, /* allowExceedsCapabilities= */ true))
.isTrue();
assertThat(tracks.isTypeSupported(C.TRACK_TYPE_TEXT, /* allowExceedsCapabilities= */ true))
.isFalse();
assertThat(tracks.isTypeSelected(C.TRACK_TYPE_AUDIO)).isFalse();
assertThat(tracks.isTypeSelected(C.TRACK_TYPE_VIDEO)).isTrue();
ImmutableList<Tracks.Group> trackGroups = tracks.getGroups();
assertThat(trackGroups).hasSize(2);
assertThat(trackGroups.get(0)).isSameInstanceAs(trackGroup0);
assertThat(trackGroups.get(1)).isSameInstanceAs(trackGroup1);
assertThat(trackGroups.get(0).isTrackSupported(0)).isFalse();
assertThat(trackGroups.get(1).isTrackSupported(0)).isFalse();
assertThat(trackGroups.get(1).isTrackSupported(1)).isTrue();
assertThat(trackGroups.get(0).getTrackSupport(0)).isEqualTo(C.FORMAT_EXCEEDS_CAPABILITIES);
assertThat(trackGroups.get(1).getTrackSupport(0)).isEqualTo(C.FORMAT_UNSUPPORTED_DRM);
assertThat(trackGroups.get(1).getTrackSupport(1)).isEqualTo(C.FORMAT_HANDLED);
assertThat(trackGroups.get(0).isTrackSelected(0)).isFalse();
assertThat(trackGroups.get(1).isTrackSelected(0)).isFalse();
assertThat(trackGroups.get(1).isTrackSelected(1)).isTrue();
assertThat(trackGroups.get(0).getType()).isEqualTo(C.TRACK_TYPE_AUDIO);
assertThat(trackGroups.get(1).getType()).isEqualTo(C.TRACK_TYPE_VIDEO);
}
/**
* Tests that {@link Tracks.Group#isAdaptiveSupported} returns false if the group only contains a
* single track, even if true is passed to the constructor.
*/
@Test
public void groupWithSingleTrack_isNotAdaptive() {
Tracks.Group trackGroup =
new Tracks.Group(
new TrackGroup(new Format.Builder().setSampleMimeType(AUDIO_AAC).build()),
/* adaptiveSupported= */ true,
new int[] {C.FORMAT_EXCEEDS_CAPABILITIES},
/* trackSelected= */ new boolean[] {false});
assertThat(trackGroup.isAdaptiveSupported()).isFalse();
}
}

View File

@ -1172,8 +1172,8 @@ public interface ExoPlayer extends Player {
/** /**
* Returns the available track groups. * Returns the available track groups.
* *
* @see Listener#onTracksInfoChanged(TracksInfo) * @see Listener#onTracksChanged(Tracks)
* @deprecated Use {@link #getCurrentTracksInfo()}. * @deprecated Use {@link #getCurrentTracks()}.
*/ */
@Deprecated @Deprecated
TrackGroupArray getCurrentTrackGroups(); TrackGroupArray getCurrentTrackGroups();
@ -1182,8 +1182,8 @@ public interface ExoPlayer extends Player {
* Returns the current track selections for each renderer, which may include {@code null} elements * Returns the current track selections for each renderer, which may include {@code null} elements
* if some renderers do not have any selected tracks. * if some renderers do not have any selected tracks.
* *
* @see Listener#onTracksInfoChanged(TracksInfo) * @see Listener#onTracksChanged(Tracks)
* @deprecated Use {@link #getCurrentTracksInfo()}. * @deprecated Use {@link #getCurrentTracks()}.
*/ */
@Deprecated @Deprecated
TrackSelectionArray getCurrentTrackSelections(); TrackSelectionArray getCurrentTrackSelections();

View File

@ -266,7 +266,7 @@ import java.util.concurrent.TimeoutException;
new TrackSelectorResult( new TrackSelectorResult(
new RendererConfiguration[renderers.length], new RendererConfiguration[renderers.length],
new ExoTrackSelection[renderers.length], new ExoTrackSelection[renderers.length],
TracksInfo.EMPTY, Tracks.EMPTY,
/* info= */ null); /* info= */ null);
period = new Timeline.Period(); period = new Timeline.Period();
permanentAvailableCommands = permanentAvailableCommands =
@ -1136,9 +1136,9 @@ import java.util.concurrent.TimeoutException;
} }
@Override @Override
public TracksInfo getCurrentTracksInfo() { public Tracks getCurrentTracks() {
verifyApplicationThread(); verifyApplicationThread();
return playbackInfo.trackSelectorResult.tracksInfo; return playbackInfo.trackSelectorResult.tracks;
} }
@Override @Override
@ -1887,7 +1887,7 @@ import java.util.concurrent.TimeoutException;
trackSelector.onSelectionActivated(newPlaybackInfo.trackSelectorResult.info); trackSelector.onSelectionActivated(newPlaybackInfo.trackSelectorResult.info);
listeners.queueEvent( listeners.queueEvent(
Player.EVENT_TRACKS_CHANGED, Player.EVENT_TRACKS_CHANGED,
listener -> listener.onTracksInfoChanged(newPlaybackInfo.trackSelectorResult.tracksInfo)); listener -> listener.onTracksChanged(newPlaybackInfo.trackSelectorResult.tracks));
} }
if (metadataChanged) { if (metadataChanged) {
final MediaMetadata finalMediaMetadata = mediaMetadata; final MediaMetadata finalMediaMetadata = mediaMetadata;

View File

@ -1049,9 +1049,9 @@ public class SimpleExoPlayer extends BasePlayer
} }
@Override @Override
public TracksInfo getCurrentTracksInfo() { public Tracks getCurrentTracks() {
blockUntilConstructorFinished(); blockUntilConstructorFinished();
return player.getCurrentTracksInfo(); return player.getCurrentTracks();
} }
@Override @Override

View File

@ -42,7 +42,7 @@ import com.google.android.exoplayer2.Player.DiscontinuityReason;
import com.google.android.exoplayer2.Player.PlaybackSuppressionReason; import com.google.android.exoplayer2.Player.PlaybackSuppressionReason;
import com.google.android.exoplayer2.Player.TimelineChangeReason; import com.google.android.exoplayer2.Player.TimelineChangeReason;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.TracksInfo; import com.google.android.exoplayer2.Tracks;
import com.google.android.exoplayer2.audio.AudioAttributes; import com.google.android.exoplayer2.audio.AudioAttributes;
import com.google.android.exoplayer2.audio.AudioSink; import com.google.android.exoplayer2.audio.AudioSink;
import com.google.android.exoplayer2.decoder.DecoderCounters; import com.google.android.exoplayer2.decoder.DecoderCounters;
@ -236,7 +236,7 @@ public interface AnalyticsListener {
* {@link Player#getCurrentMediaItem()} changed or the player started repeating the current item. * {@link Player#getCurrentMediaItem()} changed or the player started repeating the current item.
*/ */
int EVENT_MEDIA_ITEM_TRANSITION = Player.EVENT_MEDIA_ITEM_TRANSITION; int EVENT_MEDIA_ITEM_TRANSITION = Player.EVENT_MEDIA_ITEM_TRANSITION;
/** {@link Player#getCurrentTracksInfo()} changed. */ /** {@link Player#getCurrentTracks()} changed. */
int EVENT_TRACKS_CHANGED = Player.EVENT_TRACKS_CHANGED; int EVENT_TRACKS_CHANGED = Player.EVENT_TRACKS_CHANGED;
/** {@link Player#isLoading()} ()} changed. */ /** {@link Player#isLoading()} ()} changed. */
int EVENT_IS_LOADING_CHANGED = Player.EVENT_IS_LOADING_CHANGED; int EVENT_IS_LOADING_CHANGED = Player.EVENT_IS_LOADING_CHANGED;
@ -704,12 +704,12 @@ public interface AnalyticsListener {
default void onPlayerErrorChanged(EventTime eventTime, @Nullable PlaybackException error) {} default void onPlayerErrorChanged(EventTime eventTime, @Nullable PlaybackException error) {}
/** /**
* Called when the available or selected tracks change. * Called when the tracks change.
* *
* @param eventTime The event time. * @param eventTime The event time.
* @param tracksInfo The available tracks information. Never null, but may be of length zero. * @param tracks The tracks. Never null, but may be of length zero.
*/ */
default void onTracksInfoChanged(EventTime eventTime, TracksInfo tracksInfo) {} default void onTracksChanged(EventTime eventTime, Tracks tracks) {}
/** /**
* Called when track selection parameters change. * Called when track selection parameters change.

View File

@ -37,7 +37,7 @@ import com.google.android.exoplayer2.Player.PlaybackSuppressionReason;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.Timeline.Period; import com.google.android.exoplayer2.Timeline.Period;
import com.google.android.exoplayer2.Timeline.Window; import com.google.android.exoplayer2.Timeline.Window;
import com.google.android.exoplayer2.TracksInfo; import com.google.android.exoplayer2.Tracks;
import com.google.android.exoplayer2.analytics.AnalyticsListener.EventTime; import com.google.android.exoplayer2.analytics.AnalyticsListener.EventTime;
import com.google.android.exoplayer2.audio.AudioAttributes; import com.google.android.exoplayer2.audio.AudioAttributes;
import com.google.android.exoplayer2.decoder.DecoderCounters; import com.google.android.exoplayer2.decoder.DecoderCounters;
@ -481,12 +481,12 @@ public class DefaultAnalyticsCollector implements AnalyticsCollector {
} }
@Override @Override
public void onTracksInfoChanged(TracksInfo tracksInfo) { public void onTracksChanged(Tracks tracks) {
EventTime eventTime = generateCurrentPlayerMediaPeriodEventTime(); EventTime eventTime = generateCurrentPlayerMediaPeriodEventTime();
sendEvent( sendEvent(
eventTime, eventTime,
AnalyticsListener.EVENT_TRACKS_CHANGED, AnalyticsListener.EVENT_TRACKS_CHANGED,
listener -> listener.onTracksInfoChanged(eventTime, tracksInfo)); listener -> listener.onTracksChanged(eventTime, tracks));
} }
@SuppressWarnings("deprecation") // Implementing deprecated method. @SuppressWarnings("deprecation") // Implementing deprecated method.

View File

@ -49,8 +49,7 @@ import com.google.android.exoplayer2.ParserException;
import com.google.android.exoplayer2.PlaybackException; import com.google.android.exoplayer2.PlaybackException;
import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.TracksInfo; import com.google.android.exoplayer2.Tracks;
import com.google.android.exoplayer2.TracksInfo.TrackGroupInfo;
import com.google.android.exoplayer2.audio.AudioSink; import com.google.android.exoplayer2.audio.AudioSink;
import com.google.android.exoplayer2.decoder.DecoderCounters; import com.google.android.exoplayer2.decoder.DecoderCounters;
import com.google.android.exoplayer2.drm.DefaultDrmSessionManager; import com.google.android.exoplayer2.drm.DefaultDrmSessionManager;
@ -338,8 +337,7 @@ public final class MediaMetricsListener
} }
} }
if (events.contains(EVENT_TRACKS_CHANGED) && metricsBuilder != null) { if (events.contains(EVENT_TRACKS_CHANGED) && metricsBuilder != null) {
@Nullable @Nullable DrmInitData drmInitData = getDrmInitData(player.getCurrentTracks().getGroups());
DrmInitData drmInitData = getDrmInitData(player.getCurrentTracksInfo().getTrackGroupInfos());
if (drmInitData != null) { if (drmInitData != null) {
castNonNull(metricsBuilder).setDrmType(getDrmType(drmInitData)); castNonNull(metricsBuilder).setDrmType(getDrmType(drmInitData));
} }
@ -370,10 +368,10 @@ public final class MediaMetricsListener
private void maybeReportTrackChanges(Player player, Events events, long realtimeMs) { private void maybeReportTrackChanges(Player player, Events events, long realtimeMs) {
if (events.contains(EVENT_TRACKS_CHANGED)) { if (events.contains(EVENT_TRACKS_CHANGED)) {
TracksInfo tracksInfo = player.getCurrentTracksInfo(); Tracks tracks = player.getCurrentTracks();
boolean isVideoSelected = tracksInfo.isTypeSelected(C.TRACK_TYPE_VIDEO); boolean isVideoSelected = tracks.isTypeSelected(C.TRACK_TYPE_VIDEO);
boolean isAudioSelected = tracksInfo.isTypeSelected(C.TRACK_TYPE_AUDIO); boolean isAudioSelected = tracks.isTypeSelected(C.TRACK_TYPE_AUDIO);
boolean isTextSelected = tracksInfo.isTypeSelected(C.TRACK_TYPE_TEXT); boolean isTextSelected = tracks.isTypeSelected(C.TRACK_TYPE_TEXT);
if (isVideoSelected || isAudioSelected || isTextSelected) { if (isVideoSelected || isAudioSelected || isTextSelected) {
// Ignore updates with insufficient information where no tracks are selected. // Ignore updates with insufficient information where no tracks are selected.
if (!isVideoSelected) { if (!isVideoSelected) {
@ -820,11 +818,11 @@ public final class MediaMetricsListener
} }
@Nullable @Nullable
private static DrmInitData getDrmInitData(ImmutableList<TrackGroupInfo> trackGroupInfos) { private static DrmInitData getDrmInitData(ImmutableList<Tracks.Group> trackGroups) {
for (TrackGroupInfo trackGroupInfo : trackGroupInfos) { for (Tracks.Group trackGroup : trackGroups) {
for (int trackIndex = 0; trackIndex < trackGroupInfo.length; trackIndex++) { for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) {
if (trackGroupInfo.isTrackSelected(trackIndex)) { if (trackGroup.isTrackSelected(trackIndex)) {
@Nullable DrmInitData drmInitData = trackGroupInfo.getTrackFormat(trackIndex).drmInitData; @Nullable DrmInitData drmInitData = trackGroup.getTrackFormat(trackIndex).drmInitData;
if (drmInitData != null) { if (drmInitData != null) {
return drmInitData; return drmInitData;
} }

View File

@ -27,7 +27,7 @@ import com.google.android.exoplayer2.PlaybackException;
import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.Timeline.Period; import com.google.android.exoplayer2.Timeline.Period;
import com.google.android.exoplayer2.TracksInfo; import com.google.android.exoplayer2.Tracks;
import com.google.android.exoplayer2.analytics.PlaybackStats.EventTimeAndException; import com.google.android.exoplayer2.analytics.PlaybackStats.EventTimeAndException;
import com.google.android.exoplayer2.analytics.PlaybackStats.EventTimeAndFormat; import com.google.android.exoplayer2.analytics.PlaybackStats.EventTimeAndFormat;
import com.google.android.exoplayer2.analytics.PlaybackStats.EventTimeAndPlaybackState; import com.google.android.exoplayer2.analytics.PlaybackStats.EventTimeAndPlaybackState;
@ -522,11 +522,11 @@ public final class PlaybackStatsListener
hasFatalError = false; hasFatalError = false;
} }
if (isForeground && !isInterruptedByAd) { if (isForeground && !isInterruptedByAd) {
TracksInfo currentTracksInfo = player.getCurrentTracksInfo(); Tracks currentTracks = player.getCurrentTracks();
if (!currentTracksInfo.isTypeSelected(C.TRACK_TYPE_VIDEO)) { if (!currentTracks.isTypeSelected(C.TRACK_TYPE_VIDEO)) {
maybeUpdateVideoFormat(eventTime, /* newFormat= */ null); maybeUpdateVideoFormat(eventTime, /* newFormat= */ null);
} }
if (!currentTracksInfo.isTypeSelected(C.TRACK_TYPE_AUDIO)) { if (!currentTracks.isTypeSelected(C.TRACK_TYPE_AUDIO)) {
maybeUpdateAudioFormat(eventTime, /* newFormat= */ null); maybeUpdateAudioFormat(eventTime, /* newFormat= */ null);
} }
} }

View File

@ -32,7 +32,7 @@ import com.google.android.exoplayer2.Renderer;
import com.google.android.exoplayer2.RendererCapabilities; import com.google.android.exoplayer2.RendererCapabilities;
import com.google.android.exoplayer2.RenderersFactory; import com.google.android.exoplayer2.RenderersFactory;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.TracksInfo; import com.google.android.exoplayer2.Tracks;
import com.google.android.exoplayer2.analytics.PlayerId; import com.google.android.exoplayer2.analytics.PlayerId;
import com.google.android.exoplayer2.audio.AudioRendererEventListener; import com.google.android.exoplayer2.audio.AudioRendererEventListener;
import com.google.android.exoplayer2.drm.DrmSessionManager; import com.google.android.exoplayer2.drm.DrmSessionManager;
@ -543,16 +543,16 @@ public final class DownloadHelper {
} }
/** /**
* Returns {@link TracksInfo} for the given period. Must not be called until after preparation * Returns {@link Tracks} for the given period. Must not be called until after preparation
* completes. * completes.
* *
* @param periodIndex The period index. * @param periodIndex The period index.
* @return The {@link TracksInfo} for the period. May be {@link TracksInfo#EMPTY} for single * @return The {@link Tracks} for the period. May be {@link Tracks#EMPTY} for single stream
* stream content. * content.
*/ */
public TracksInfo getTracksInfo(int periodIndex) { public Tracks getTracks(int periodIndex) {
assertPreparedWithMedia(); assertPreparedWithMedia();
return TrackSelectionUtil.buildTracksInfo( return TrackSelectionUtil.buildTracks(
mappedTrackInfos[periodIndex], immutableTrackSelectionsByPeriodAndRenderer[periodIndex]); mappedTrackInfos[periodIndex], immutableTrackSelectionsByPeriodAndRenderer[periodIndex]);
} }

View File

@ -1955,12 +1955,11 @@ public class DefaultTrackSelector extends MappingTrackSelector {
if (override == null) { if (override == null) {
continue; continue;
} }
@Nullable @Nullable TrackSelectionOverride existingOverride = overridesByType.get(override.getType());
TrackSelectionOverride existingOverride = overridesByType.get(override.getTrackType());
// Only replace an existing override if it's empty and the one being considered is not. // Only replace an existing override if it's empty and the one being considered is not.
if (existingOverride == null if (existingOverride == null
|| (existingOverride.trackIndices.isEmpty() && !override.trackIndices.isEmpty())) { || (existingOverride.trackIndices.isEmpty() && !override.trackIndices.isEmpty())) {
overridesByType.put(override.getTrackType(), override); overridesByType.put(override.getType(), override);
} }
} }
} }

View File

@ -36,7 +36,7 @@ import com.google.android.exoplayer2.RendererCapabilities.AdaptiveSupport;
import com.google.android.exoplayer2.RendererCapabilities.Capabilities; import com.google.android.exoplayer2.RendererCapabilities.Capabilities;
import com.google.android.exoplayer2.RendererConfiguration; import com.google.android.exoplayer2.RendererConfiguration;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.TracksInfo; import com.google.android.exoplayer2.Tracks;
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;
@ -425,9 +425,9 @@ public abstract class MappingTrackSelector extends TrackSelector {
periodId, periodId,
timeline); timeline);
TracksInfo tracksInfo = TrackSelectionUtil.buildTracksInfo(mappedTrackInfo, result.second); Tracks tracks = TrackSelectionUtil.buildTracks(mappedTrackInfo, result.second);
return new TrackSelectorResult(result.first, result.second, tracksInfo, mappedTrackInfo); return new TrackSelectorResult(result.first, result.second, tracks, mappedTrackInfo);
} }
/** /**

View File

@ -19,8 +19,7 @@ import android.os.SystemClock;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.RendererCapabilities; import com.google.android.exoplayer2.RendererCapabilities;
import com.google.android.exoplayer2.TracksInfo; import com.google.android.exoplayer2.Tracks;
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.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;
@ -134,16 +133,16 @@ public final class TrackSelectionUtil {
} }
/** /**
* Returns {@link TracksInfo} built from {@link MappingTrackSelector.MappedTrackInfo} and {@link * Returns {@link Tracks} built from {@link MappingTrackSelector.MappedTrackInfo} and {@link
* TrackSelection TrackSelections} for each renderer. * TrackSelection TrackSelections} for each renderer.
* *
* @param mappedTrackInfo The {@link MappingTrackSelector.MappedTrackInfo} * @param mappedTrackInfo The {@link MappingTrackSelector.MappedTrackInfo}
* @param selections The track selections, indexed by renderer. A null entry indicates that a * @param selections The track selections, indexed by renderer. A null entry indicates that a
* renderer does not have any selected tracks. * renderer does not have any selected tracks.
* @return The corresponding {@link TracksInfo}. * @return The corresponding {@link Tracks}.
*/ */
@SuppressWarnings({"unchecked", "rawtypes"}) // Initialization of array of Lists. @SuppressWarnings({"unchecked", "rawtypes"}) // Initialization of array of Lists.
public static TracksInfo buildTracksInfo( public static Tracks buildTracks(
MappingTrackSelector.MappedTrackInfo mappedTrackInfo, MappingTrackSelector.MappedTrackInfo mappedTrackInfo,
@NullableType TrackSelection[] selections) { @NullableType TrackSelection[] selections) {
List<? extends TrackSelection>[] listSelections = new List[selections.length]; List<? extends TrackSelection>[] listSelections = new List[selections.length];
@ -151,22 +150,22 @@ public final class TrackSelectionUtil {
@Nullable TrackSelection selection = selections[i]; @Nullable TrackSelection selection = selections[i];
listSelections[i] = selection != null ? ImmutableList.of(selection) : ImmutableList.of(); listSelections[i] = selection != null ? ImmutableList.of(selection) : ImmutableList.of();
} }
return buildTracksInfo(mappedTrackInfo, listSelections); return buildTracks(mappedTrackInfo, listSelections);
} }
/** /**
* Returns {@link TracksInfo} built from {@link MappingTrackSelector.MappedTrackInfo} and {@link * Returns {@link Tracks} built from {@link MappingTrackSelector.MappedTrackInfo} and {@link
* TrackSelection TrackSelections} for each renderer. * TrackSelection TrackSelections} for each renderer.
* *
* @param mappedTrackInfo The {@link MappingTrackSelector.MappedTrackInfo} * @param mappedTrackInfo The {@link MappingTrackSelector.MappedTrackInfo}
* @param selections The track selections, indexed by renderer. Null entries are not permitted. An * @param selections The track selections, indexed by renderer. Null entries are not permitted. An
* empty list indicates that a renderer does not have any selected tracks. * empty list indicates that a renderer does not have any selected tracks.
* @return The corresponding {@link TracksInfo}. * @return The corresponding {@link Tracks}.
*/ */
public static TracksInfo buildTracksInfo( public static Tracks buildTracks(
MappingTrackSelector.MappedTrackInfo mappedTrackInfo, MappingTrackSelector.MappedTrackInfo mappedTrackInfo,
List<? extends TrackSelection>[] selections) { List<? extends TrackSelection>[] selections) {
ImmutableList.Builder<TrackGroupInfo> trackGroupInfos = new ImmutableList.Builder<>(); ImmutableList.Builder<Tracks.Group> trackGroups = new ImmutableList.Builder<>();
for (int rendererIndex = 0; for (int rendererIndex = 0;
rendererIndex < mappedTrackInfo.getRendererCount(); rendererIndex < mappedTrackInfo.getRendererCount();
rendererIndex++) { rendererIndex++) {
@ -194,8 +193,7 @@ public final class TrackSelectionUtil {
} }
selected[trackIndex] = isTrackSelected; selected[trackIndex] = isTrackSelected;
} }
trackGroupInfos.add( trackGroups.add(new Tracks.Group(trackGroup, adaptiveSupported, trackSupport, selected));
new TrackGroupInfo(trackGroup, adaptiveSupported, trackSupport, selected));
} }
} }
TrackGroupArray unmappedTrackGroups = mappedTrackInfo.getUnmappedTrackGroups(); TrackGroupArray unmappedTrackGroups = mappedTrackInfo.getUnmappedTrackGroups();
@ -204,9 +202,9 @@ public final class TrackSelectionUtil {
@C.FormatSupport int[] trackSupport = new int[trackGroup.length]; @C.FormatSupport int[] trackSupport = new int[trackGroup.length];
Arrays.fill(trackSupport, C.FORMAT_UNSUPPORTED_TYPE); Arrays.fill(trackSupport, C.FORMAT_UNSUPPORTED_TYPE);
boolean[] selected = new boolean[trackGroup.length]; boolean[] selected = new boolean[trackGroup.length];
trackGroupInfos.add( trackGroups.add(
new TrackGroupInfo(trackGroup, /* adaptiveSupported= */ false, trackSupport, selected)); new Tracks.Group(trackGroup, /* adaptiveSupported= */ false, trackSupport, selected));
} }
return new TracksInfo(trackGroupInfos.build()); return new Tracks(trackGroups.build());
} }
} }

View File

@ -17,7 +17,7 @@ package com.google.android.exoplayer2.trackselection;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.google.android.exoplayer2.RendererConfiguration; import com.google.android.exoplayer2.RendererConfiguration;
import com.google.android.exoplayer2.TracksInfo; import com.google.android.exoplayer2.Tracks;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import org.checkerframework.checker.nullness.compatqual.NullableType; import org.checkerframework.checker.nullness.compatqual.NullableType;
@ -34,7 +34,7 @@ public final class TrackSelectorResult {
/** A {@link ExoTrackSelection} array containing the track selection for each renderer. */ /** A {@link ExoTrackSelection} array containing the track selection for each renderer. */
public final @NullableType ExoTrackSelection[] selections; public final @NullableType ExoTrackSelection[] selections;
/** Describe the tracks and which one were selected. */ /** Describe the tracks and which one were selected. */
public final TracksInfo tracksInfo; public final Tracks tracks;
/** /**
* An opaque object that will be returned to {@link TrackSelector#onSelectionActivated(Object)} * An opaque object that will be returned to {@link TrackSelector#onSelectionActivated(Object)}
* should the selections be activated. * should the selections be activated.
@ -49,21 +49,21 @@ public final class TrackSelectorResult {
* TrackSelector#onSelectionActivated(Object)} should the selection be activated. May be * TrackSelector#onSelectionActivated(Object)} should the selection be activated. May be
* {@code null}. * {@code null}.
* @deprecated Use {@link #TrackSelectorResult(RendererConfiguration[], ExoTrackSelection[], * @deprecated Use {@link #TrackSelectorResult(RendererConfiguration[], ExoTrackSelection[],
* TracksInfo, Object)}. * Tracks, Object)}.
*/ */
@Deprecated @Deprecated
public TrackSelectorResult( public TrackSelectorResult(
@NullableType RendererConfiguration[] rendererConfigurations, @NullableType RendererConfiguration[] rendererConfigurations,
@NullableType ExoTrackSelection[] selections, @NullableType ExoTrackSelection[] selections,
@Nullable Object info) { @Nullable Object info) {
this(rendererConfigurations, selections, TracksInfo.EMPTY, info); this(rendererConfigurations, selections, Tracks.EMPTY, info);
} }
/** /**
* @param rendererConfigurations A {@link RendererConfiguration} for each renderer. A null entry * @param rendererConfigurations A {@link RendererConfiguration} for each renderer. A null entry
* indicates the corresponding renderer should be disabled. * indicates the corresponding renderer should be disabled.
* @param selections A {@link ExoTrackSelection} array containing the selection for each renderer. * @param selections A {@link ExoTrackSelection} array containing the selection for each renderer.
* @param tracksInfo Description of the available tracks and which one were selected. * @param tracks Description of the available tracks and which one were selected.
* @param info An opaque object that will be returned to {@link * @param info An opaque object that will be returned to {@link
* TrackSelector#onSelectionActivated(Object)} should the selection be activated. May be * TrackSelector#onSelectionActivated(Object)} should the selection be activated. May be
* {@code null}. * {@code null}.
@ -71,11 +71,11 @@ public final class TrackSelectorResult {
public TrackSelectorResult( public TrackSelectorResult(
@NullableType RendererConfiguration[] rendererConfigurations, @NullableType RendererConfiguration[] rendererConfigurations,
@NullableType ExoTrackSelection[] selections, @NullableType ExoTrackSelection[] selections,
TracksInfo tracksInfo, Tracks tracks,
@Nullable Object info) { @Nullable Object info) {
this.rendererConfigurations = rendererConfigurations; this.rendererConfigurations = rendererConfigurations;
this.selections = selections.clone(); this.selections = selections.clone();
this.tracksInfo = tracksInfo; this.tracks = tracks;
this.info = info; this.info = info;
length = rendererConfigurations.length; length = rendererConfigurations.length;
} }

View File

@ -29,7 +29,7 @@ import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Player.PlaybackSuppressionReason; import com.google.android.exoplayer2.Player.PlaybackSuppressionReason;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.TracksInfo; import com.google.android.exoplayer2.Tracks;
import com.google.android.exoplayer2.analytics.AnalyticsListener; import com.google.android.exoplayer2.analytics.AnalyticsListener;
import com.google.android.exoplayer2.audio.AudioAttributes; import com.google.android.exoplayer2.audio.AudioAttributes;
import com.google.android.exoplayer2.decoder.DecoderCounters; import com.google.android.exoplayer2.decoder.DecoderCounters;
@ -258,23 +258,23 @@ public class EventLogger implements AnalyticsListener {
} }
@Override @Override
public void onTracksInfoChanged(EventTime eventTime, TracksInfo tracksInfo) { public void onTracksChanged(EventTime eventTime, Tracks tracks) {
logd("tracks [" + getEventTimeString(eventTime)); logd("tracks [" + getEventTimeString(eventTime));
// Log tracks associated to renderers. // Log tracks associated to renderers.
ImmutableList<TracksInfo.TrackGroupInfo> trackGroupInfos = tracksInfo.getTrackGroupInfos(); ImmutableList<Tracks.Group> trackGroups = tracks.getGroups();
for (int groupIndex = 0; groupIndex < trackGroupInfos.size(); groupIndex++) { for (int groupIndex = 0; groupIndex < trackGroups.size(); groupIndex++) {
TracksInfo.TrackGroupInfo trackGroupInfo = trackGroupInfos.get(groupIndex); Tracks.Group trackGroup = trackGroups.get(groupIndex);
logd(" group ["); logd(" group [");
for (int trackIndex = 0; trackIndex < trackGroupInfo.length; trackIndex++) { for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) {
String status = getTrackStatusString(trackGroupInfo.isTrackSelected(trackIndex)); String status = getTrackStatusString(trackGroup.isTrackSelected(trackIndex));
String formatSupport = getFormatSupportString(trackGroupInfo.getTrackSupport(trackIndex)); String formatSupport = getFormatSupportString(trackGroup.getTrackSupport(trackIndex));
logd( logd(
" " " "
+ status + status
+ " Track:" + " Track:"
+ trackIndex + trackIndex
+ ", " + ", "
+ Format.toLogString(trackGroupInfo.getTrackFormat(trackIndex)) + Format.toLogString(trackGroup.getTrackFormat(trackIndex))
+ ", supported=" + ", supported="
+ formatSupport); + formatSupport);
} }
@ -283,8 +283,8 @@ public class EventLogger implements AnalyticsListener {
// TODO: Replace this with an override of onMediaMetadataChanged. // TODO: Replace this with an override of onMediaMetadataChanged.
// Log metadata for at most one of the selected tracks. // Log metadata for at most one of the selected tracks.
boolean loggedMetadata = false; boolean loggedMetadata = false;
for (int groupIndex = 0; !loggedMetadata && groupIndex < trackGroupInfos.size(); groupIndex++) { for (int groupIndex = 0; !loggedMetadata && groupIndex < trackGroups.size(); groupIndex++) {
TracksInfo.TrackGroupInfo trackGroup = trackGroupInfos.get(groupIndex); Tracks.Group trackGroup = trackGroups.get(groupIndex);
for (int trackIndex = 0; !loggedMetadata && trackIndex < trackGroup.length; trackIndex++) { for (int trackIndex = 0; !loggedMetadata && trackIndex < trackGroup.length; trackIndex++) {
if (trackGroup.isTrackSelected(trackIndex)) { if (trackGroup.isTrackSelected(trackIndex)) {
@Nullable Metadata metadata = trackGroup.getTrackFormat(trackIndex).metadata; @Nullable Metadata metadata = trackGroup.getTrackFormat(trackIndex).metadata;

View File

@ -96,7 +96,6 @@ import com.google.android.exoplayer2.Player.DiscontinuityReason;
import com.google.android.exoplayer2.Player.Listener; import com.google.android.exoplayer2.Player.Listener;
import com.google.android.exoplayer2.Player.PositionInfo; import com.google.android.exoplayer2.Player.PositionInfo;
import com.google.android.exoplayer2.Timeline.Window; import com.google.android.exoplayer2.Timeline.Window;
import com.google.android.exoplayer2.TracksInfo.TrackGroupInfo;
import com.google.android.exoplayer2.analytics.AnalyticsListener; import com.google.android.exoplayer2.analytics.AnalyticsListener;
import com.google.android.exoplayer2.audio.AudioAttributes; import com.google.android.exoplayer2.audio.AudioAttributes;
import com.google.android.exoplayer2.drm.DrmSessionEventListener; import com.google.android.exoplayer2.drm.DrmSessionEventListener;
@ -267,15 +266,15 @@ public final class ExoPlayerTest {
argThat(noUid(timeline)), eq(Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE)); argThat(noUid(timeline)), eq(Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE));
inOrder inOrder
.verify(mockListener) .verify(mockListener)
.onTracksInfoChanged( .onTracksChanged(
eq( eq(
new TracksInfo( new Tracks(
ImmutableList.of( ImmutableList.of(
new TrackGroupInfo( new Tracks.Group(
new TrackGroup(ExoPlayerTestRunner.VIDEO_FORMAT), new TrackGroup(ExoPlayerTestRunner.VIDEO_FORMAT),
/* adaptiveSupported= */ false, /* adaptiveSupported= */ false,
new int[] {C.FORMAT_HANDLED}, new int[] {C.FORMAT_HANDLED},
/* tracksSelected= */ new boolean[] {true}))))); /* trackSelected= */ new boolean[] {true})))));
inOrder.verify(mockListener, never()).onPositionDiscontinuity(anyInt()); inOrder.verify(mockListener, never()).onPositionDiscontinuity(anyInt());
inOrder.verify(mockListener, never()).onPositionDiscontinuity(any(), any(), anyInt()); inOrder.verify(mockListener, never()).onPositionDiscontinuity(any(), any(), anyInt());
assertThat(renderer.getFormatsRead()).containsExactly(ExoPlayerTestRunner.VIDEO_FORMAT); assertThat(renderer.getFormatsRead()).containsExactly(ExoPlayerTestRunner.VIDEO_FORMAT);
@ -646,15 +645,15 @@ public final class ExoPlayerTest {
argThat(noUid(thirdTimeline)), eq(Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE)); argThat(noUid(thirdTimeline)), eq(Player.TIMELINE_CHANGE_REASON_SOURCE_UPDATE));
inOrder inOrder
.verify(mockPlayerListener) .verify(mockPlayerListener)
.onTracksInfoChanged( .onTracksChanged(
eq( eq(
new TracksInfo( new Tracks(
ImmutableList.of( ImmutableList.of(
new TrackGroupInfo( new Tracks.Group(
new TrackGroup(ExoPlayerTestRunner.VIDEO_FORMAT), new TrackGroup(ExoPlayerTestRunner.VIDEO_FORMAT),
/* adaptiveSupported= */ false, /* adaptiveSupported= */ false,
new int[] {C.FORMAT_HANDLED}, new int[] {C.FORMAT_HANDLED},
/* tracksSelected= */ new boolean[] {true}))))); /* trackSelected= */ new boolean[] {true})))));
assertThat(renderer.isEnded).isTrue(); assertThat(renderer.isEnded).isTrue();
} }
@ -3416,7 +3415,7 @@ public final class ExoPlayerTest {
.waitForPendingPlayerCommands() .waitForPendingPlayerCommands()
.play() .play()
.build(); .build();
List<TracksInfo> tracksInfoList = new ArrayList<>(); List<Tracks> tracksList = new ArrayList<>();
new ExoPlayerTestRunner.Builder(context) new ExoPlayerTestRunner.Builder(context)
.setMediaSources(mediaSource) .setMediaSources(mediaSource)
.setSupportedFormats(ExoPlayerTestRunner.VIDEO_FORMAT, ExoPlayerTestRunner.AUDIO_FORMAT) .setSupportedFormats(ExoPlayerTestRunner.VIDEO_FORMAT, ExoPlayerTestRunner.AUDIO_FORMAT)
@ -3424,21 +3423,21 @@ public final class ExoPlayerTest {
.setPlayerListener( .setPlayerListener(
new Player.Listener() { new Player.Listener() {
@Override @Override
public void onTracksInfoChanged(TracksInfo tracksInfo) { public void onTracksChanged(Tracks tracks) {
tracksInfoList.add(tracksInfo); tracksList.add(tracks);
} }
}) })
.build() .build()
.start() .start()
.blockUntilEnded(TIMEOUT_MS); .blockUntilEnded(TIMEOUT_MS);
assertThat(tracksInfoList).hasSize(3); assertThat(tracksList).hasSize(3);
// First track groups of the 1st period are reported. // First track groups of the 1st period are reported.
// Then the seek to an unprepared period will result in empty track groups being returned. // Then the seek to an unprepared period will result in empty track groups being returned.
// Then the track groups of the 2nd period are reported. // Then the track groups of the 2nd period are reported.
assertThat(tracksInfoList.get(0).getTrackGroupInfos().get(0).getTrackFormat(0)) assertThat(tracksList.get(0).getGroups().get(0).getTrackFormat(0))
.isEqualTo(ExoPlayerTestRunner.VIDEO_FORMAT); .isEqualTo(ExoPlayerTestRunner.VIDEO_FORMAT);
assertThat(tracksInfoList.get(1)).isEqualTo(TracksInfo.EMPTY); assertThat(tracksList.get(1)).isEqualTo(Tracks.EMPTY);
assertThat(tracksInfoList.get(2).getTrackGroupInfos().get(0).getTrackFormat(0)) assertThat(tracksList.get(2).getGroups().get(0).getTrackFormat(0))
.isEqualTo(ExoPlayerTestRunner.AUDIO_FORMAT); .isEqualTo(ExoPlayerTestRunner.AUDIO_FORMAT);
} }
@ -7983,7 +7982,7 @@ public final class ExoPlayerTest {
} }
}; };
AtomicReference<Timeline> timelineAfterError = new AtomicReference<>(); AtomicReference<Timeline> timelineAfterError = new AtomicReference<>();
AtomicReference<TracksInfo> trackInfosAfterError = new AtomicReference<>(); AtomicReference<Tracks> trackInfosAfterError = new AtomicReference<>();
AtomicInteger mediaItemIndexAfterError = new AtomicInteger(); AtomicInteger mediaItemIndexAfterError = new AtomicInteger();
ActionSchedule actionSchedule = ActionSchedule actionSchedule =
new ActionSchedule.Builder(TAG) new ActionSchedule.Builder(TAG)
@ -7996,7 +7995,7 @@ public final class ExoPlayerTest {
@Override @Override
public void onPlayerError(EventTime eventTime, PlaybackException error) { public void onPlayerError(EventTime eventTime, PlaybackException error) {
timelineAfterError.set(player.getCurrentTimeline()); timelineAfterError.set(player.getCurrentTimeline());
trackInfosAfterError.set(player.getCurrentTracksInfo()); trackInfosAfterError.set(player.getCurrentTracks());
mediaItemIndexAfterError.set(player.getCurrentMediaItemIndex()); mediaItemIndexAfterError.set(player.getCurrentMediaItemIndex());
} }
}); });
@ -8025,8 +8024,8 @@ public final class ExoPlayerTest {
assertThat(timelineAfterError.get().getWindowCount()).isEqualTo(1); assertThat(timelineAfterError.get().getWindowCount()).isEqualTo(1);
assertThat(mediaItemIndexAfterError.get()).isEqualTo(0); assertThat(mediaItemIndexAfterError.get()).isEqualTo(0);
assertThat(trackInfosAfterError.get().getTrackGroupInfos()).hasSize(1); assertThat(trackInfosAfterError.get().getGroups()).hasSize(1);
assertThat(trackInfosAfterError.get().getTrackGroupInfos().get(0).getTrackFormat(0)) assertThat(trackInfosAfterError.get().getGroups().get(0).getTrackFormat(0))
.isEqualTo(ExoPlayerTestRunner.AUDIO_FORMAT); .isEqualTo(ExoPlayerTestRunner.AUDIO_FORMAT);
assertThat(trackInfosAfterError.get().isTypeSelected(C.TRACK_TYPE_VIDEO)).isFalse(); assertThat(trackInfosAfterError.get().isTypeSelected(C.TRACK_TYPE_VIDEO)).isFalse();
assertThat(trackInfosAfterError.get().isTypeSelected(C.TRACK_TYPE_AUDIO)).isTrue(); assertThat(trackInfosAfterError.get().isTypeSelected(C.TRACK_TYPE_AUDIO)).isTrue();
@ -10413,7 +10412,7 @@ public final class ExoPlayerTest {
verify(listener, atLeastOnce()).onShuffleModeEnabledChanged(anyBoolean()); verify(listener, atLeastOnce()).onShuffleModeEnabledChanged(anyBoolean());
verify(listener, atLeastOnce()).onPlaybackStateChanged(anyInt()); verify(listener, atLeastOnce()).onPlaybackStateChanged(anyInt());
verify(listener, atLeastOnce()).onIsLoadingChanged(anyBoolean()); verify(listener, atLeastOnce()).onIsLoadingChanged(anyBoolean());
verify(listener, atLeastOnce()).onTracksInfoChanged(any()); verify(listener, atLeastOnce()).onTracksChanged(any());
verify(listener, atLeastOnce()).onMediaMetadataChanged(any()); verify(listener, atLeastOnce()).onMediaMetadataChanged(any());
verify(listener, atLeastOnce()).onPlayWhenReadyChanged(anyBoolean(), anyInt()); verify(listener, atLeastOnce()).onPlayWhenReadyChanged(anyBoolean(), anyInt());
verify(listener, atLeastOnce()).onIsPlayingChanged(anyBoolean()); verify(listener, atLeastOnce()).onIsPlayingChanged(anyBoolean());

View File

@ -1135,7 +1135,7 @@ public final class MediaPeriodQueueTest {
new TrackSelectorResult( new TrackSelectorResult(
new RendererConfiguration[0], new RendererConfiguration[0],
new ExoTrackSelection[0], new ExoTrackSelection[0],
TracksInfo.EMPTY, Tracks.EMPTY,
/* info= */ null)); /* info= */ null));
} }

View File

@ -83,7 +83,7 @@ import com.google.android.exoplayer2.Renderer;
import com.google.android.exoplayer2.RenderersFactory; import com.google.android.exoplayer2.RenderersFactory;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.Timeline.Window; import com.google.android.exoplayer2.Timeline.Window;
import com.google.android.exoplayer2.TracksInfo; import com.google.android.exoplayer2.Tracks;
import com.google.android.exoplayer2.decoder.DecoderCounters; import com.google.android.exoplayer2.decoder.DecoderCounters;
import com.google.android.exoplayer2.drm.DefaultDrmSessionManager; import com.google.android.exoplayer2.drm.DefaultDrmSessionManager;
import com.google.android.exoplayer2.drm.DrmInitData; import com.google.android.exoplayer2.drm.DrmInitData;
@ -1729,7 +1729,7 @@ public final class DefaultAnalyticsCollectorTest {
ArgumentCaptor<AnalyticsListener.EventTime> individualTracksChangedEventTimes = ArgumentCaptor<AnalyticsListener.EventTime> individualTracksChangedEventTimes =
ArgumentCaptor.forClass(AnalyticsListener.EventTime.class); ArgumentCaptor.forClass(AnalyticsListener.EventTime.class);
verify(listener, atLeastOnce()) verify(listener, atLeastOnce())
.onTracksInfoChanged(individualTracksChangedEventTimes.capture(), any()); .onTracksChanged(individualTracksChangedEventTimes.capture(), any());
ArgumentCaptor<AnalyticsListener.EventTime> individualPlayWhenReadyChangedEventTimes = ArgumentCaptor<AnalyticsListener.EventTime> individualPlayWhenReadyChangedEventTimes =
ArgumentCaptor.forClass(AnalyticsListener.EventTime.class); ArgumentCaptor.forClass(AnalyticsListener.EventTime.class);
verify(listener, atLeastOnce()) verify(listener, atLeastOnce())
@ -2243,7 +2243,7 @@ public final class DefaultAnalyticsCollectorTest {
} }
@Override @Override
public void onTracksInfoChanged(EventTime eventTime, TracksInfo tracksInfo) { public void onTracksChanged(EventTime eventTime, Tracks tracks) {
reportedEvents.add(new ReportedEvent(EVENT_TRACKS_CHANGED, eventTime)); reportedEvents.add(new ReportedEvent(EVENT_TRACKS_CHANGED, eventTime));
} }

View File

@ -44,7 +44,7 @@ import com.google.android.exoplayer2.RendererCapabilities;
import com.google.android.exoplayer2.RendererCapabilities.Capabilities; import com.google.android.exoplayer2.RendererCapabilities.Capabilities;
import com.google.android.exoplayer2.RendererConfiguration; import com.google.android.exoplayer2.RendererConfiguration;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.TracksInfo; import com.google.android.exoplayer2.Tracks;
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;
@ -2223,10 +2223,10 @@ public final class DefaultTrackSelectorTest {
public void selectTracks_multipleRenderer_allSelected() throws Exception { public void selectTracks_multipleRenderer_allSelected() throws Exception {
RendererCapabilities[] rendererCapabilities = RendererCapabilities[] rendererCapabilities =
new RendererCapabilities[] {VIDEO_CAPABILITIES, AUDIO_CAPABILITIES, AUDIO_CAPABILITIES}; new RendererCapabilities[] {VIDEO_CAPABILITIES, AUDIO_CAPABILITIES, AUDIO_CAPABILITIES};
TrackGroupArray trackGroups = new TrackGroupArray(AUDIO_TRACK_GROUP); TrackGroupArray trackGroupArray = new TrackGroupArray(AUDIO_TRACK_GROUP);
TrackSelectorResult result = TrackSelectorResult result =
trackSelector.selectTracks(rendererCapabilities, trackGroups, periodId, TIMELINE); trackSelector.selectTracks(rendererCapabilities, trackGroupArray, periodId, TIMELINE);
assertThat(result.length).isEqualTo(3); assertThat(result.length).isEqualTo(3);
assertThat(result.rendererConfigurations) assertThat(result.rendererConfigurations)
@ -2234,14 +2234,14 @@ public final class DefaultTrackSelectorTest {
.containsExactly(null, DEFAULT, null) .containsExactly(null, DEFAULT, null)
.inOrder(); .inOrder();
assertThat(result.selections[0]).isNull(); assertThat(result.selections[0]).isNull();
assertFixedSelection(result.selections[1], trackGroups, trackGroups.get(0).getFormat(0)); assertFixedSelection(
result.selections[1], trackGroupArray, trackGroupArray.get(0).getFormat(0));
assertThat(result.selections[2]).isNull(); assertThat(result.selections[2]).isNull();
ImmutableList<TracksInfo.TrackGroupInfo> trackGroupInfos = ImmutableList<Tracks.Group> trackGroups = result.tracks.getGroups();
result.tracksInfo.getTrackGroupInfos(); assertThat(trackGroups).hasSize(1);
assertThat(trackGroupInfos).hasSize(1); assertThat(trackGroups.get(0).getTrackGroup()).isEqualTo(AUDIO_TRACK_GROUP);
assertThat(trackGroupInfos.get(0).getTrackGroup()).isEqualTo(AUDIO_TRACK_GROUP); assertThat(trackGroups.get(0).isTrackSelected(0)).isTrue();
assertThat(trackGroupInfos.get(0).isTrackSelected(0)).isTrue(); assertThat(trackGroups.get(0).getTrackSupport(0)).isEqualTo(FORMAT_HANDLED);
assertThat(trackGroupInfos.get(0).getTrackSupport(0)).isEqualTo(FORMAT_HANDLED);
} }
/** Tests {@link SelectionOverride}'s {@link Bundleable} implementation. */ /** Tests {@link SelectionOverride}'s {@link Bundleable} implementation. */

View File

@ -32,8 +32,7 @@ import static com.google.common.truth.Truth.assertThat;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.TracksInfo; import com.google.android.exoplayer2.Tracks;
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.source.TrackGroupArray; import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList;
@ -73,32 +72,32 @@ public class TrackSelectionUtilTest {
new FixedTrackSelection(mappedTrackInfo.getTrackGroups(1).get(0), 1) new FixedTrackSelection(mappedTrackInfo.getTrackGroups(1).get(0), 1)
}; };
TracksInfo tracksInfo = TrackSelectionUtil.buildTracksInfo(mappedTrackInfo, selections); Tracks tracks = TrackSelectionUtil.buildTracks(mappedTrackInfo, selections);
ImmutableList<TracksInfo.TrackGroupInfo> trackGroupInfos = tracksInfo.getTrackGroupInfos(); ImmutableList<Tracks.Group> trackGroups = tracks.getGroups();
assertThat(trackGroupInfos).hasSize(4); assertThat(trackGroups).hasSize(4);
assertThat(trackGroupInfos.get(0).getTrackGroup()) assertThat(trackGroups.get(0).getTrackGroup())
.isEqualTo(mappedTrackInfo.getTrackGroups(0).get(0)); .isEqualTo(mappedTrackInfo.getTrackGroups(0).get(0));
assertThat(trackGroupInfos.get(1).getTrackGroup()) assertThat(trackGroups.get(1).getTrackGroup())
.isEqualTo(mappedTrackInfo.getTrackGroups(0).get(1)); .isEqualTo(mappedTrackInfo.getTrackGroups(0).get(1));
assertThat(trackGroupInfos.get(2).getTrackGroup()) assertThat(trackGroups.get(2).getTrackGroup())
.isEqualTo(mappedTrackInfo.getTrackGroups(1).get(0)); .isEqualTo(mappedTrackInfo.getTrackGroups(1).get(0));
assertThat(trackGroupInfos.get(3).getTrackGroup()) assertThat(trackGroups.get(3).getTrackGroup())
.isEqualTo(mappedTrackInfo.getUnmappedTrackGroups().get(0)); .isEqualTo(mappedTrackInfo.getUnmappedTrackGroups().get(0));
assertThat(trackGroupInfos.get(0).getTrackSupport(0)).isEqualTo(FORMAT_HANDLED); assertThat(trackGroups.get(0).getTrackSupport(0)).isEqualTo(FORMAT_HANDLED);
assertThat(trackGroupInfos.get(1).getTrackSupport(0)).isEqualTo(FORMAT_UNSUPPORTED_SUBTYPE); assertThat(trackGroups.get(1).getTrackSupport(0)).isEqualTo(FORMAT_UNSUPPORTED_SUBTYPE);
assertThat(trackGroupInfos.get(2).getTrackSupport(0)).isEqualTo(FORMAT_UNSUPPORTED_DRM); assertThat(trackGroups.get(2).getTrackSupport(0)).isEqualTo(FORMAT_UNSUPPORTED_DRM);
assertThat(trackGroupInfos.get(2).getTrackSupport(1)).isEqualTo(FORMAT_EXCEEDS_CAPABILITIES); assertThat(trackGroups.get(2).getTrackSupport(1)).isEqualTo(FORMAT_EXCEEDS_CAPABILITIES);
assertThat(trackGroupInfos.get(3).getTrackSupport(0)).isEqualTo(FORMAT_UNSUPPORTED_TYPE); assertThat(trackGroups.get(3).getTrackSupport(0)).isEqualTo(FORMAT_UNSUPPORTED_TYPE);
assertThat(trackGroupInfos.get(0).isTrackSelected(0)).isFalse(); assertThat(trackGroups.get(0).isTrackSelected(0)).isFalse();
assertThat(trackGroupInfos.get(1).isTrackSelected(0)).isTrue(); assertThat(trackGroups.get(1).isTrackSelected(0)).isTrue();
assertThat(trackGroupInfos.get(2).isTrackSelected(0)).isFalse(); assertThat(trackGroups.get(2).isTrackSelected(0)).isFalse();
assertThat(trackGroupInfos.get(2).isTrackSelected(1)).isTrue(); assertThat(trackGroups.get(2).isTrackSelected(1)).isTrue();
assertThat(trackGroupInfos.get(3).isTrackSelected(0)).isFalse(); assertThat(trackGroups.get(3).isTrackSelected(0)).isFalse();
assertThat(trackGroupInfos.get(0).getTrackType()).isEqualTo(TRACK_TYPE_AUDIO); assertThat(trackGroups.get(0).getType()).isEqualTo(TRACK_TYPE_AUDIO);
assertThat(trackGroupInfos.get(1).getTrackType()).isEqualTo(TRACK_TYPE_AUDIO); assertThat(trackGroups.get(1).getType()).isEqualTo(TRACK_TYPE_AUDIO);
assertThat(trackGroupInfos.get(2).getTrackType()).isEqualTo(TRACK_TYPE_VIDEO); assertThat(trackGroups.get(2).getType()).isEqualTo(TRACK_TYPE_VIDEO);
assertThat(trackGroupInfos.get(3).getTrackType()).isEqualTo(TRACK_TYPE_UNKNOWN); assertThat(trackGroups.get(3).getType()).isEqualTo(TRACK_TYPE_UNKNOWN);
} }
@Test @Test
@ -132,21 +131,21 @@ public class TrackSelectionUtilTest {
ImmutableList.of() ImmutableList.of()
}; };
TracksInfo tracksInfo = TrackSelectionUtil.buildTracksInfo(mappedTrackInfo, selections); Tracks tracks = TrackSelectionUtil.buildTracks(mappedTrackInfo, selections);
ImmutableList<TrackGroupInfo> trackGroupInfos = tracksInfo.getTrackGroupInfos(); ImmutableList<Tracks.Group> trackGroups = tracks.getGroups();
assertThat(trackGroupInfos).hasSize(2); assertThat(trackGroups).hasSize(2);
assertThat(trackGroupInfos.get(0).getTrackGroup()) assertThat(trackGroups.get(0).getTrackGroup())
.isEqualTo(mappedTrackInfo.getTrackGroups(0).get(0)); .isEqualTo(mappedTrackInfo.getTrackGroups(0).get(0));
assertThat(trackGroupInfos.get(1).getTrackGroup()) assertThat(trackGroups.get(1).getTrackGroup())
.isEqualTo(mappedTrackInfo.getTrackGroups(0).get(1)); .isEqualTo(mappedTrackInfo.getTrackGroups(0).get(1));
assertThat(trackGroupInfos.get(0).getTrackSupport(0)).isEqualTo(FORMAT_HANDLED); assertThat(trackGroups.get(0).getTrackSupport(0)).isEqualTo(FORMAT_HANDLED);
assertThat(trackGroupInfos.get(1).getTrackSupport(0)).isEqualTo(FORMAT_HANDLED); assertThat(trackGroups.get(1).getTrackSupport(0)).isEqualTo(FORMAT_HANDLED);
assertThat(trackGroupInfos.get(1).getTrackSupport(1)).isEqualTo(FORMAT_HANDLED); assertThat(trackGroups.get(1).getTrackSupport(1)).isEqualTo(FORMAT_HANDLED);
assertThat(trackGroupInfos.get(0).isTrackSelected(0)).isTrue(); assertThat(trackGroups.get(0).isTrackSelected(0)).isTrue();
assertThat(trackGroupInfos.get(1).isTrackSelected(0)).isFalse(); assertThat(trackGroups.get(1).isTrackSelected(0)).isFalse();
assertThat(trackGroupInfos.get(1).isTrackSelected(1)).isTrue(); assertThat(trackGroups.get(1).isTrackSelected(1)).isTrue();
assertThat(trackGroupInfos.get(0).getTrackType()).isEqualTo(TRACK_TYPE_AUDIO); assertThat(trackGroups.get(0).getType()).isEqualTo(TRACK_TYPE_AUDIO);
assertThat(trackGroupInfos.get(1).getTrackType()).isEqualTo(TRACK_TYPE_AUDIO); assertThat(trackGroups.get(1).getType()).isEqualTo(TRACK_TYPE_AUDIO);
} }
} }

View File

@ -44,7 +44,7 @@ import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Renderer; import com.google.android.exoplayer2.Renderer;
import com.google.android.exoplayer2.RenderersFactory; import com.google.android.exoplayer2.RenderersFactory;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.TracksInfo; import com.google.android.exoplayer2.Tracks;
import com.google.android.exoplayer2.audio.AudioRendererEventListener; import com.google.android.exoplayer2.audio.AudioRendererEventListener;
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory; import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
import com.google.android.exoplayer2.extractor.mp4.Mp4Extractor; import com.google.android.exoplayer2.extractor.mp4.Mp4Extractor;
@ -947,7 +947,7 @@ public final class Transformer {
} }
@Override @Override
public void onTracksInfoChanged(TracksInfo tracksInfo) { public void onTracksChanged(Tracks tracks) {
if (muxerWrapper.getTrackCount() == 0) { if (muxerWrapper.getTrackCount() == 0) {
handleTransformationEnded( handleTransformationEnded(
TransformationException.createForUnexpected( TransformationException.createForUnexpected(

View File

@ -53,7 +53,7 @@ import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Player.DiscontinuityReason; import com.google.android.exoplayer2.Player.DiscontinuityReason;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.Timeline.Period; import com.google.android.exoplayer2.Timeline.Period;
import com.google.android.exoplayer2.TracksInfo; import com.google.android.exoplayer2.Tracks;
import com.google.android.exoplayer2.text.Cue; import com.google.android.exoplayer2.text.Cue;
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout.ResizeMode; import com.google.android.exoplayer2.ui.AspectRatioFrameLayout.ResizeMode;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
@ -1230,7 +1230,7 @@ public class PlayerView extends FrameLayout implements AdViewProvider {
@Nullable Player player = this.player; @Nullable Player player = this.player;
if (player == null if (player == null
|| !player.isCommandAvailable(Player.COMMAND_GET_TRACK_INFOS) || !player.isCommandAvailable(Player.COMMAND_GET_TRACK_INFOS)
|| player.getCurrentTracksInfo().getTrackGroupInfos().isEmpty()) { || player.getCurrentTracks().isEmpty()) {
if (!keepContentOnPlayerReset) { if (!keepContentOnPlayerReset) {
hideArtwork(); hideArtwork();
closeShutter(); closeShutter();
@ -1242,7 +1242,7 @@ public class PlayerView extends FrameLayout implements AdViewProvider {
// Hide any video from the previous player. // Hide any video from the previous player.
closeShutter(); closeShutter();
} }
if (player.getCurrentTracksInfo().isTypeSelected(C.TRACK_TYPE_VIDEO)) { if (player.getCurrentTracks().isTypeSelected(C.TRACK_TYPE_VIDEO)) {
// Video enabled, so artwork must be hidden. If the shutter is closed, it will be opened // Video enabled, so artwork must be hidden. If the shutter is closed, it will be opened
// in onRenderedFirstFrame(). // in onRenderedFirstFrame().
hideArtwork(); hideArtwork();
@ -1474,7 +1474,7 @@ public class PlayerView extends FrameLayout implements AdViewProvider {
} }
@Override @Override
public void onTracksInfoChanged(TracksInfo tracksInfo) { public void onTracksChanged(Tracks tracks) {
// Suppress the update if transitioning to an unprepared period within the same window. This // Suppress the update if transitioning to an unprepared period within the same window. This
// is necessary to avoid closing the shutter when such a transition occurs. See: // is necessary to avoid closing the shutter when such a transition occurs. See:
// https://github.com/google/ExoPlayer/issues/5507. // https://github.com/google/ExoPlayer/issues/5507.
@ -1482,7 +1482,7 @@ public class PlayerView extends FrameLayout implements AdViewProvider {
Timeline timeline = player.getCurrentTimeline(); Timeline timeline = player.getCurrentTimeline();
if (timeline.isEmpty()) { if (timeline.isEmpty()) {
lastPeriodUidWithTracks = null; lastPeriodUidWithTracks = null;
} else if (!player.getCurrentTracksInfo().getTrackGroupInfos().isEmpty()) { } else if (!player.getCurrentTracks().isEmpty()) {
lastPeriodUidWithTracks = lastPeriodUidWithTracks =
timeline.getPeriod(player.getCurrentPeriodIndex(), period, /* setIds= */ true).uid; timeline.getPeriod(player.getCurrentPeriodIndex(), period, /* setIds= */ true).uid;
} else if (lastPeriodUidWithTracks != null) { } else if (lastPeriodUidWithTracks != null) {

View File

@ -65,8 +65,7 @@ import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Player.Events; import com.google.android.exoplayer2.Player.Events;
import com.google.android.exoplayer2.Player.State; import com.google.android.exoplayer2.Player.State;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.TracksInfo; import com.google.android.exoplayer2.Tracks;
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.TrackSelectionOverride; import com.google.android.exoplayer2.trackselection.TrackSelectionOverride;
import com.google.android.exoplayer2.trackselection.TrackSelectionParameters; import com.google.android.exoplayer2.trackselection.TrackSelectionParameters;
@ -1107,39 +1106,37 @@ public class StyledPlayerControlView extends FrameLayout {
|| !player.isCommandAvailable(Player.COMMAND_SET_TRACK_SELECTION_PARAMETERS)) { || !player.isCommandAvailable(Player.COMMAND_SET_TRACK_SELECTION_PARAMETERS)) {
return; return;
} }
TracksInfo tracksInfo = player.getCurrentTracksInfo(); Tracks tracks = player.getCurrentTracks();
audioTrackSelectionAdapter.init( audioTrackSelectionAdapter.init(gatherSupportedTrackInfosOfType(tracks, C.TRACK_TYPE_AUDIO));
gatherSupportedTrackInfosOfType(tracksInfo, C.TRACK_TYPE_AUDIO));
if (controlViewLayoutManager.getShowButton(subtitleButton)) { if (controlViewLayoutManager.getShowButton(subtitleButton)) {
textTrackSelectionAdapter.init( textTrackSelectionAdapter.init(gatherSupportedTrackInfosOfType(tracks, C.TRACK_TYPE_TEXT));
gatherSupportedTrackInfosOfType(tracksInfo, C.TRACK_TYPE_TEXT));
} else { } else {
textTrackSelectionAdapter.init(ImmutableList.of()); textTrackSelectionAdapter.init(ImmutableList.of());
} }
} }
private ImmutableList<TrackInformation> gatherSupportedTrackInfosOfType( private ImmutableList<TrackInformation> gatherSupportedTrackInfosOfType(
TracksInfo tracksInfo, @C.TrackType int trackType) { Tracks tracks, @C.TrackType int trackType) {
ImmutableList.Builder<TrackInformation> tracks = new ImmutableList.Builder<>(); ImmutableList.Builder<TrackInformation> trackInfos = new ImmutableList.Builder<>();
List<TrackGroupInfo> trackGroupInfos = tracksInfo.getTrackGroupInfos(); List<Tracks.Group> trackGroups = tracks.getGroups();
for (int trackGroupIndex = 0; trackGroupIndex < trackGroupInfos.size(); trackGroupIndex++) { for (int trackGroupIndex = 0; trackGroupIndex < trackGroups.size(); trackGroupIndex++) {
TrackGroupInfo trackGroupInfo = trackGroupInfos.get(trackGroupIndex); Tracks.Group trackGroup = trackGroups.get(trackGroupIndex);
if (trackGroupInfo.getTrackType() != trackType) { if (trackGroup.getType() != trackType) {
continue; continue;
} }
for (int trackIndex = 0; trackIndex < trackGroupInfo.length; trackIndex++) { for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) {
if (!trackGroupInfo.isTrackSupported(trackIndex)) { if (!trackGroup.isTrackSupported(trackIndex)) {
continue; continue;
} }
Format trackFormat = trackGroupInfo.getTrackFormat(trackIndex); Format trackFormat = trackGroup.getTrackFormat(trackIndex);
if ((trackFormat.selectionFlags & C.SELECTION_FLAG_FORCED) != 0) { if ((trackFormat.selectionFlags & C.SELECTION_FLAG_FORCED) != 0) {
continue; continue;
} }
String trackName = trackNameProvider.getTrackName(trackFormat); String trackName = trackNameProvider.getTrackName(trackFormat);
tracks.add(new TrackInformation(tracksInfo, trackGroupIndex, trackIndex, trackName)); trackInfos.add(new TrackInformation(tracks, trackGroupIndex, trackIndex, trackName));
} }
} }
return tracks.build(); return trackInfos.build();
} }
private void updateTimeline() { private void updateTimeline() {
@ -1818,19 +1815,18 @@ public class StyledPlayerControlView extends FrameLayout {
private static final class TrackInformation { private static final class TrackInformation {
public final TrackGroupInfo trackGroupInfo; public final Tracks.Group trackGroup;
public final int trackIndex; public final int trackIndex;
public final String trackName; public final String trackName;
public TrackInformation( public TrackInformation(Tracks tracks, int trackGroupIndex, int trackIndex, String trackName) {
TracksInfo tracksInfo, int trackGroupIndex, int trackIndex, String trackName) { this.trackGroup = tracks.getGroups().get(trackGroupIndex);
this.trackGroupInfo = tracksInfo.getTrackGroupInfos().get(trackGroupIndex);
this.trackIndex = trackIndex; this.trackIndex = trackIndex;
this.trackName = trackName; this.trackName = trackName;
} }
public boolean isSelected() { public boolean isSelected() {
return trackGroupInfo.isTrackSelected(trackIndex); return trackGroup.isTrackSelected(trackIndex);
} }
} }
@ -1930,7 +1926,7 @@ public class StyledPlayerControlView extends FrameLayout {
private boolean hasSelectionOverride(TrackSelectionParameters trackSelectionParameters) { private boolean hasSelectionOverride(TrackSelectionParameters trackSelectionParameters) {
for (int i = 0; i < tracks.size(); i++) { for (int i = 0; i < tracks.size(); i++) {
TrackGroup trackGroup = tracks.get(i).trackGroupInfo.getTrackGroup(); TrackGroup trackGroup = tracks.get(i).trackGroup.getTrackGroup();
if (trackSelectionParameters.overrides.containsKey(trackGroup)) { if (trackSelectionParameters.overrides.containsKey(trackGroup)) {
return true; return true;
} }
@ -2004,7 +2000,7 @@ public class StyledPlayerControlView extends FrameLayout {
onBindViewHolderAtZeroPosition(holder); onBindViewHolderAtZeroPosition(holder);
} else { } else {
TrackInformation track = tracks.get(position - 1); TrackInformation track = tracks.get(position - 1);
TrackGroup trackGroup = track.trackGroupInfo.getTrackGroup(); TrackGroup trackGroup = track.trackGroup.getTrackGroup();
TrackSelectionParameters params = player.getTrackSelectionParameters(); TrackSelectionParameters params = player.getTrackSelectionParameters();
boolean explicitlySelected = params.overrides.get(trackGroup) != null && track.isSelected(); boolean explicitlySelected = params.overrides.get(trackGroup) != null && track.isSelected();
holder.textView.setText(track.trackName); holder.textView.setText(track.trackName);
@ -2019,8 +2015,7 @@ public class StyledPlayerControlView extends FrameLayout {
.setOverrideForType( .setOverrideForType(
new TrackSelectionOverride( new TrackSelectionOverride(
trackGroup, ImmutableList.of(track.trackIndex))) trackGroup, ImmutableList.of(track.trackIndex)))
.setTrackTypeDisabled( .setTrackTypeDisabled(track.trackGroup.getType(), /* disabled= */ false)
track.trackGroupInfo.getTrackType(), /* disabled= */ false)
.build()); .build());
onTrackSelection(track.trackName); onTrackSelection(track.trackName);
settingsWindow.dismiss(); settingsWindow.dismiss();

View File

@ -55,7 +55,7 @@ import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Player.DiscontinuityReason; import com.google.android.exoplayer2.Player.DiscontinuityReason;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.Timeline.Period; import com.google.android.exoplayer2.Timeline.Period;
import com.google.android.exoplayer2.TracksInfo; import com.google.android.exoplayer2.Tracks;
import com.google.android.exoplayer2.text.Cue; import com.google.android.exoplayer2.text.Cue;
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout.ResizeMode; import com.google.android.exoplayer2.ui.AspectRatioFrameLayout.ResizeMode;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
@ -1177,7 +1177,7 @@ public class StyledPlayerView extends FrameLayout implements AdViewProvider {
private void updateForCurrentTrackSelections(boolean isNewPlayer) { private void updateForCurrentTrackSelections(boolean isNewPlayer) {
@Nullable Player player = this.player; @Nullable Player player = this.player;
if (player == null || player.getCurrentTracksInfo().getTrackGroupInfos().isEmpty()) { if (player == null || player.getCurrentTracks().isEmpty()) {
if (!keepContentOnPlayerReset) { if (!keepContentOnPlayerReset) {
hideArtwork(); hideArtwork();
closeShutter(); closeShutter();
@ -1190,7 +1190,7 @@ public class StyledPlayerView extends FrameLayout implements AdViewProvider {
closeShutter(); closeShutter();
} }
if (player.getCurrentTracksInfo().isTypeSelected(C.TRACK_TYPE_VIDEO)) { if (player.getCurrentTracks().isTypeSelected(C.TRACK_TYPE_VIDEO)) {
// Video enabled, so artwork must be hidden. If the shutter is closed, it will be opened // Video enabled, so artwork must be hidden. If the shutter is closed, it will be opened
// in onRenderedFirstFrame(). // in onRenderedFirstFrame().
hideArtwork(); hideArtwork();
@ -1422,7 +1422,7 @@ public class StyledPlayerView extends FrameLayout implements AdViewProvider {
} }
@Override @Override
public void onTracksInfoChanged(TracksInfo tracksInfo) { public void onTracksChanged(Tracks tracks) {
// Suppress the update if transitioning to an unprepared period within the same window. This // Suppress the update if transitioning to an unprepared period within the same window. This
// is necessary to avoid closing the shutter when such a transition occurs. See: // is necessary to avoid closing the shutter when such a transition occurs. See:
// https://github.com/google/ExoPlayer/issues/5507. // https://github.com/google/ExoPlayer/issues/5507.
@ -1430,7 +1430,7 @@ public class StyledPlayerView extends FrameLayout implements AdViewProvider {
Timeline timeline = player.getCurrentTimeline(); Timeline timeline = player.getCurrentTimeline();
if (timeline.isEmpty()) { if (timeline.isEmpty()) {
lastPeriodUidWithTracks = null; lastPeriodUidWithTracks = null;
} else if (!player.getCurrentTracksInfo().getTrackGroupInfos().isEmpty()) { } else if (!player.getCurrentTracks().isEmpty()) {
lastPeriodUidWithTracks = lastPeriodUidWithTracks =
timeline.getPeriod(player.getCurrentPeriodIndex(), period, /* setIds= */ true).uid; timeline.getPeriod(player.getCurrentPeriodIndex(), period, /* setIds= */ true).uid;
} else if (lastPeriodUidWithTracks != null) { } else if (lastPeriodUidWithTracks != null) {

View File

@ -26,7 +26,7 @@ import androidx.annotation.StyleRes;
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.Player; import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.TracksInfo.TrackGroupInfo; import com.google.android.exoplayer2.Tracks;
import com.google.android.exoplayer2.source.TrackGroup; import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.trackselection.TrackSelectionOverride; import com.google.android.exoplayer2.trackselection.TrackSelectionOverride;
import com.google.android.exoplayer2.trackselection.TrackSelectionParameters; import com.google.android.exoplayer2.trackselection.TrackSelectionParameters;
@ -56,7 +56,7 @@ public final class TrackSelectionDialogBuilder {
private final Context context; private final Context context;
private final CharSequence title; private final CharSequence title;
private final List<TrackGroupInfo> trackGroupInfos; private final List<Tracks.Group> trackGroups;
private final DialogCallback callback; private final DialogCallback callback;
@StyleRes private int themeResId; @StyleRes private int themeResId;
@ -73,17 +73,17 @@ public final class TrackSelectionDialogBuilder {
* *
* @param context The context of the dialog. * @param context The context of the dialog.
* @param title The title of the dialog. * @param title The title of the dialog.
* @param trackGroupInfos The {@link TrackGroupInfo TrackGroupInfos} for the track groups. * @param trackGroups The {@link Tracks.Group track groups}.
* @param callback The {@link DialogCallback} invoked when a track selection has been made. * @param callback The {@link DialogCallback} invoked when a track selection has been made.
*/ */
public TrackSelectionDialogBuilder( public TrackSelectionDialogBuilder(
Context context, Context context,
CharSequence title, CharSequence title,
List<TrackGroupInfo> trackGroupInfos, List<Tracks.Group> trackGroups,
DialogCallback callback) { DialogCallback callback) {
this.context = context; this.context = context;
this.title = title; this.title = title;
this.trackGroupInfos = ImmutableList.copyOf(trackGroupInfos); this.trackGroups = ImmutableList.copyOf(trackGroups);
this.callback = callback; this.callback = callback;
overrides = Collections.emptyMap(); overrides = Collections.emptyMap();
} }
@ -100,12 +100,12 @@ public final class TrackSelectionDialogBuilder {
Context context, CharSequence title, Player player, @C.TrackType int trackType) { Context context, CharSequence title, Player player, @C.TrackType int trackType) {
this.context = context; this.context = context;
this.title = title; this.title = title;
List<TrackGroupInfo> allTrackGroupInfos = player.getCurrentTracksInfo().getTrackGroupInfos(); List<Tracks.Group> allTrackGroups = player.getCurrentTracks().getGroups();
trackGroupInfos = new ArrayList<>(); trackGroups = new ArrayList<>();
for (int i = 0; i < allTrackGroupInfos.size(); i++) { for (int i = 0; i < allTrackGroups.size(); i++) {
TrackGroupInfo trackGroupInfo = allTrackGroupInfos.get(i); Tracks.Group trackGroup = allTrackGroups.get(i);
if (trackGroupInfo.getTrackType() == trackType) { if (trackGroup.getType() == trackType) {
trackGroupInfos.add(trackGroupInfo); trackGroups.add(trackGroup);
} }
} }
overrides = Collections.emptyMap(); overrides = Collections.emptyMap();
@ -156,11 +156,11 @@ public final class TrackSelectionDialogBuilder {
} }
/** /**
* Sets the initial track overrides. Any overrides that do not correspond to track groups * Sets the initial track overrides. Any overrides that do not correspond to track groups that
* described by {@code trackGroupInfos} that have been given to this instance will be ignored. If * were passed to the constructor will be ignored. If {@link #setAllowMultipleOverrides(boolean)}
* {@link #setAllowMultipleOverrides(boolean)} hasn't been set to {@code true} then all but one * hasn't been set to {@code true} then all but one override will be ignored. The retained
* override will be ignored. The retained override will be the one whose track group is described * override will be the one whose track group was first in the list of track groups passed to the
* first in {@code trackGroupInfos}. * constructor.
* *
* @param overrides The initially selected track overrides. * @param overrides The initially selected track overrides.
* @return This builder, for convenience. * @return This builder, for convenience.
@ -296,7 +296,7 @@ public final class TrackSelectionDialogBuilder {
selectionView.setTrackNameProvider(trackNameProvider); selectionView.setTrackNameProvider(trackNameProvider);
} }
selectionView.init( selectionView.init(
trackGroupInfos, isDisabled, overrides, trackFormatComparator, /* listener= */ null); trackGroups, isDisabled, overrides, trackFormatComparator, /* listener= */ null);
return (dialog, which) -> return (dialog, which) ->
callback.onTracksSelected(selectionView.getIsDisabled(), selectionView.getOverrides()); callback.onTracksSelected(selectionView.getIsDisabled(), selectionView.getOverrides());
} }

View File

@ -25,7 +25,7 @@ import android.widget.LinearLayout;
import androidx.annotation.AttrRes; import androidx.annotation.AttrRes;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.TracksInfo.TrackGroupInfo; import com.google.android.exoplayer2.Tracks;
import com.google.android.exoplayer2.source.TrackGroup; import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.trackselection.TrackSelectionOverride; import com.google.android.exoplayer2.trackselection.TrackSelectionOverride;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
@ -54,23 +54,23 @@ public class TrackSelectionView extends LinearLayout {
} }
/** /**
* Returns the subset of {@code overrides} that apply to track groups in {@code trackGroupInfos}. * Returns the subset of {@code overrides} that apply to the specified {@code trackGroups}. If
* If {@code allowMultipleOverrides} is {@code} then at most one override is retained, which will * {@code allowMultipleOverrides} is {@code} then at most one override is retained, which will be
* be the one whose track group is first in {@code trackGroupInfos}. * the one whose track group is first in {@code trackGroups}.
* *
* @param overrides The overrides to filter. * @param overrides The overrides to filter.
* @param trackGroupInfos The track groups whose overrides should be retained. * @param trackGroups The track groups whose overrides should be retained.
* @param allowMultipleOverrides Whether more than one override can be retained. * @param allowMultipleOverrides Whether more than one override can be retained.
* @return The filtered overrides. * @return The filtered overrides.
*/ */
public static Map<TrackGroup, TrackSelectionOverride> filterOverrides( public static Map<TrackGroup, TrackSelectionOverride> filterOverrides(
Map<TrackGroup, TrackSelectionOverride> overrides, Map<TrackGroup, TrackSelectionOverride> overrides,
List<TrackGroupInfo> trackGroupInfos, List<Tracks.Group> trackGroups,
boolean allowMultipleOverrides) { boolean allowMultipleOverrides) {
HashMap<TrackGroup, TrackSelectionOverride> filteredOverrides = new HashMap<>(); HashMap<TrackGroup, TrackSelectionOverride> filteredOverrides = new HashMap<>();
for (int i = 0; i < trackGroupInfos.size(); i++) { for (int i = 0; i < trackGroups.size(); i++) {
TrackGroupInfo trackGroupInfo = trackGroupInfos.get(i); Tracks.Group trackGroup = trackGroups.get(i);
@Nullable TrackSelectionOverride override = overrides.get(trackGroupInfo.getTrackGroup()); @Nullable TrackSelectionOverride override = overrides.get(trackGroup.getTrackGroup());
if (override != null && (allowMultipleOverrides || filteredOverrides.isEmpty())) { if (override != null && (allowMultipleOverrides || filteredOverrides.isEmpty())) {
filteredOverrides.put(override.trackGroup, override); filteredOverrides.put(override.trackGroup, override);
} }
@ -83,7 +83,7 @@ public class TrackSelectionView extends LinearLayout {
private final CheckedTextView disableView; private final CheckedTextView disableView;
private final CheckedTextView defaultView; private final CheckedTextView defaultView;
private final ComponentListener componentListener; private final ComponentListener componentListener;
private final List<TrackGroupInfo> trackGroupInfos; private final List<Tracks.Group> trackGroups;
private final Map<TrackGroup, TrackSelectionOverride> overrides; private final Map<TrackGroup, TrackSelectionOverride> overrides;
private boolean allowAdaptiveSelections; private boolean allowAdaptiveSelections;
@ -125,7 +125,7 @@ public class TrackSelectionView extends LinearLayout {
inflater = LayoutInflater.from(context); inflater = LayoutInflater.from(context);
componentListener = new ComponentListener(); componentListener = new ComponentListener();
trackNameProvider = new DefaultTrackNameProvider(getResources()); trackNameProvider = new DefaultTrackNameProvider(getResources());
trackGroupInfos = new ArrayList<>(); trackGroups = new ArrayList<>();
overrides = new HashMap<>(); overrides = new HashMap<>();
// View for disabling the renderer. // View for disabling the renderer.
@ -181,7 +181,7 @@ public class TrackSelectionView extends LinearLayout {
if (!allowMultipleOverrides && overrides.size() > 1) { if (!allowMultipleOverrides && overrides.size() > 1) {
// Re-filter the overrides to retain only one of them. // Re-filter the overrides to retain only one of them.
Map<TrackGroup, TrackSelectionOverride> filteredOverrides = Map<TrackGroup, TrackSelectionOverride> filteredOverrides =
filterOverrides(overrides, trackGroupInfos, /* allowMultipleOverrides= */ false); filterOverrides(overrides, trackGroups, /* allowMultipleOverrides= */ false);
overrides.clear(); overrides.clear();
overrides.putAll(filteredOverrides); overrides.putAll(filteredOverrides);
} }
@ -212,19 +212,19 @@ public class TrackSelectionView extends LinearLayout {
/** /**
* Initialize the view to select tracks from a specified list of track groups. * Initialize the view to select tracks from a specified list of track groups.
* *
* @param trackGroupInfos {@link TrackGroupInfo TrackGroupInfos} for the track groups. * @param trackGroups The {@link Tracks.Group track groups}.
* @param isDisabled Whether the disabled option should be initially selected. * @param isDisabled Whether the disabled option should be initially selected.
* @param overrides The initially selected track overrides. Any overrides that do not correspond * @param overrides The initially selected track overrides. Any overrides that do not correspond
* to track groups described in {@code trackGroupInfos} will be ignored. If {@link * to track groups in {@code trackGroups} will be ignored. If {@link
* #setAllowMultipleOverrides(boolean)} hasn't been set to {@code true} then all but one * #setAllowMultipleOverrides(boolean)} hasn't been set to {@code true} then all but one
* override will be ignored. The retained override will be the one whose track group is * override will be ignored. The retained override will be the one whose track group is first
* described first in {@code trackGroupInfos}. * in {@code trackGroups}.
* @param trackFormatComparator An optional comparator used to determine the display order of the * @param trackFormatComparator An optional comparator used to determine the display order of the
* tracks within each track group. * tracks within each track group.
* @param listener An optional listener to receive selection updates. * @param listener An optional listener to receive selection updates.
*/ */
public void init( public void init(
List<TrackGroupInfo> trackGroupInfos, List<Tracks.Group> trackGroups,
boolean isDisabled, boolean isDisabled,
Map<TrackGroup, TrackSelectionOverride> overrides, Map<TrackGroup, TrackSelectionOverride> overrides,
@Nullable Comparator<Format> trackFormatComparator, @Nullable Comparator<Format> trackFormatComparator,
@ -236,10 +236,10 @@ public class TrackSelectionView extends LinearLayout {
: (o1, o2) -> trackFormatComparator.compare(o1.getFormat(), o2.getFormat()); : (o1, o2) -> trackFormatComparator.compare(o1.getFormat(), o2.getFormat());
this.listener = listener; this.listener = listener;
this.trackGroupInfos.clear(); this.trackGroups.clear();
this.trackGroupInfos.addAll(trackGroupInfos); this.trackGroups.addAll(trackGroups);
this.overrides.clear(); this.overrides.clear();
this.overrides.putAll(filterOverrides(overrides, trackGroupInfos, allowMultipleOverrides)); this.overrides.putAll(filterOverrides(overrides, trackGroups, allowMultipleOverrides));
updateViews(); updateViews();
} }
@ -261,7 +261,7 @@ public class TrackSelectionView extends LinearLayout {
removeViewAt(i); removeViewAt(i);
} }
if (trackGroupInfos.isEmpty()) { if (trackGroups.isEmpty()) {
// The view is not initialized. // The view is not initialized.
disableView.setEnabled(false); disableView.setEnabled(false);
defaultView.setEnabled(false); defaultView.setEnabled(false);
@ -271,17 +271,16 @@ public class TrackSelectionView extends LinearLayout {
defaultView.setEnabled(true); defaultView.setEnabled(true);
// Add per-track views. // Add per-track views.
trackViews = new CheckedTextView[trackGroupInfos.size()][]; trackViews = new CheckedTextView[trackGroups.size()][];
boolean enableMultipleChoiceForMultipleOverrides = shouldEnableMultiGroupSelection(); boolean enableMultipleChoiceForMultipleOverrides = shouldEnableMultiGroupSelection();
for (int trackGroupIndex = 0; trackGroupIndex < trackGroupInfos.size(); trackGroupIndex++) { for (int trackGroupIndex = 0; trackGroupIndex < trackGroups.size(); trackGroupIndex++) {
TrackGroupInfo trackGroupInfo = trackGroupInfos.get(trackGroupIndex); Tracks.Group trackGroup = trackGroups.get(trackGroupIndex);
boolean enableMultipleChoiceForAdaptiveSelections = boolean enableMultipleChoiceForAdaptiveSelections = shouldEnableAdaptiveSelection(trackGroup);
shouldEnableAdaptiveSelection(trackGroupInfo); trackViews[trackGroupIndex] = new CheckedTextView[trackGroup.length];
trackViews[trackGroupIndex] = new CheckedTextView[trackGroupInfo.length];
TrackInfo[] trackInfos = new TrackInfo[trackGroupInfo.length]; TrackInfo[] trackInfos = new TrackInfo[trackGroup.length];
for (int trackIndex = 0; trackIndex < trackGroupInfo.length; trackIndex++) { for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) {
trackInfos[trackIndex] = new TrackInfo(trackGroupInfo, trackIndex); trackInfos[trackIndex] = new TrackInfo(trackGroup, trackIndex);
} }
if (trackInfoComparator != null) { if (trackInfoComparator != null) {
Arrays.sort(trackInfos, trackInfoComparator); Arrays.sort(trackInfos, trackInfoComparator);
@ -300,7 +299,7 @@ public class TrackSelectionView extends LinearLayout {
trackView.setBackgroundResource(selectableItemBackgroundResourceId); trackView.setBackgroundResource(selectableItemBackgroundResourceId);
trackView.setText(trackNameProvider.getTrackName(trackInfos[trackIndex].getFormat())); trackView.setText(trackNameProvider.getTrackName(trackInfos[trackIndex].getFormat()));
trackView.setTag(trackInfos[trackIndex]); trackView.setTag(trackInfos[trackIndex]);
if (trackGroupInfo.isTrackSupported(trackIndex)) { if (trackGroup.isTrackSupported(trackIndex)) {
trackView.setFocusable(true); trackView.setFocusable(true);
trackView.setOnClickListener(componentListener); trackView.setOnClickListener(componentListener);
} else { } else {
@ -319,8 +318,7 @@ public class TrackSelectionView extends LinearLayout {
disableView.setChecked(isDisabled); disableView.setChecked(isDisabled);
defaultView.setChecked(!isDisabled && overrides.size() == 0); defaultView.setChecked(!isDisabled && overrides.size() == 0);
for (int i = 0; i < trackViews.length; i++) { for (int i = 0; i < trackViews.length; i++) {
@Nullable @Nullable TrackSelectionOverride override = overrides.get(trackGroups.get(i).getTrackGroup());
TrackSelectionOverride override = overrides.get(trackGroupInfos.get(i).getTrackGroup());
for (int j = 0; j < trackViews[i].length; j++) { for (int j = 0; j < trackViews[i].length; j++) {
if (override != null) { if (override != null) {
TrackInfo trackInfo = (TrackInfo) Assertions.checkNotNull(trackViews[i][j].getTag()); TrackInfo trackInfo = (TrackInfo) Assertions.checkNotNull(trackViews[i][j].getTag());
@ -359,7 +357,7 @@ public class TrackSelectionView extends LinearLayout {
private void onTrackViewClicked(View view) { private void onTrackViewClicked(View view) {
isDisabled = false; isDisabled = false;
TrackInfo trackInfo = (TrackInfo) Assertions.checkNotNull(view.getTag()); TrackInfo trackInfo = (TrackInfo) Assertions.checkNotNull(view.getTag());
TrackGroup trackGroup = trackInfo.trackGroupInfo.getTrackGroup(); TrackGroup trackGroup = trackInfo.trackGroup.getTrackGroup();
int trackIndex = trackInfo.trackIndex; int trackIndex = trackInfo.trackIndex;
@Nullable TrackSelectionOverride override = overrides.get(trackGroup); @Nullable TrackSelectionOverride override = overrides.get(trackGroup);
if (override == null) { if (override == null) {
@ -374,7 +372,7 @@ public class TrackSelectionView extends LinearLayout {
// An existing override is being modified. // An existing override is being modified.
ArrayList<Integer> trackIndices = new ArrayList<>(override.trackIndices); ArrayList<Integer> trackIndices = new ArrayList<>(override.trackIndices);
boolean isCurrentlySelected = ((CheckedTextView) view).isChecked(); boolean isCurrentlySelected = ((CheckedTextView) view).isChecked();
boolean isAdaptiveAllowed = shouldEnableAdaptiveSelection(trackInfo.trackGroupInfo); boolean isAdaptiveAllowed = shouldEnableAdaptiveSelection(trackInfo.trackGroup);
boolean isUsingCheckBox = isAdaptiveAllowed || shouldEnableMultiGroupSelection(); boolean isUsingCheckBox = isAdaptiveAllowed || shouldEnableMultiGroupSelection();
if (isCurrentlySelected && isUsingCheckBox) { if (isCurrentlySelected && isUsingCheckBox) {
// Remove the track from the override. // Remove the track from the override.
@ -399,12 +397,12 @@ public class TrackSelectionView extends LinearLayout {
} }
} }
private boolean shouldEnableAdaptiveSelection(TrackGroupInfo trackGroupInfo) { private boolean shouldEnableAdaptiveSelection(Tracks.Group trackGroup) {
return allowAdaptiveSelections && trackGroupInfo.isAdaptiveSupported(); return allowAdaptiveSelections && trackGroup.isAdaptiveSupported();
} }
private boolean shouldEnableMultiGroupSelection() { private boolean shouldEnableMultiGroupSelection() {
return allowMultipleOverrides && trackGroupInfos.size() > 1; return allowMultipleOverrides && trackGroups.size() > 1;
} }
// Internal classes. // Internal classes.
@ -418,16 +416,16 @@ public class TrackSelectionView extends LinearLayout {
} }
private static final class TrackInfo { private static final class TrackInfo {
public final TrackGroupInfo trackGroupInfo; public final Tracks.Group trackGroup;
public final int trackIndex; public final int trackIndex;
public TrackInfo(TrackGroupInfo trackGroupInfo, int trackIndex) { public TrackInfo(Tracks.Group trackGroup, int trackIndex) {
this.trackGroupInfo = trackGroupInfo; this.trackGroup = trackGroup;
this.trackIndex = trackIndex; this.trackIndex = trackIndex;
} }
public Format getFormat() { public Format getFormat() {
return trackGroupInfo.getTrackFormat(trackIndex); return trackGroup.getTrackFormat(trackIndex);
} }
} }
} }

View File

@ -29,7 +29,7 @@ import com.google.android.exoplayer2.PlaybackException;
import com.google.android.exoplayer2.PlaybackParameters; import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.TracksInfo; import com.google.android.exoplayer2.Tracks;
import com.google.android.exoplayer2.audio.AudioAttributes; import com.google.android.exoplayer2.audio.AudioAttributes;
import com.google.android.exoplayer2.text.Cue; import com.google.android.exoplayer2.text.Cue;
import com.google.android.exoplayer2.trackselection.TrackSelectionParameters; import com.google.android.exoplayer2.trackselection.TrackSelectionParameters;
@ -189,7 +189,7 @@ public class StubPlayer extends BasePlayer {
} }
@Override @Override
public TracksInfo getCurrentTracksInfo() { public Tracks getCurrentTracks() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }