Commit 98ee159d by krocard Committed by Oliver Woodman

Use TracksInfo and selection override in users

Update the UI module, the demos and most other users
to make use of the new player TracksInfo and track
selection override APIs.

PiperOrigin-RevId: 402817857
parent fe0a5662
...@@ -19,7 +19,6 @@ import android.content.Context; ...@@ -19,7 +19,6 @@ import android.content.Context;
import android.view.KeyEvent; import android.view.KeyEvent;
import android.view.View; import android.view.View;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.MediaItem; import com.google.android.exoplayer2.MediaItem;
...@@ -28,12 +27,9 @@ import com.google.android.exoplayer2.Player.DiscontinuityReason; ...@@ -28,12 +27,9 @@ 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.SimpleExoPlayer; import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.TracksInfo;
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.source.TrackGroupArray;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.MappingTrackSelector;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import com.google.android.exoplayer2.ui.PlayerControlView; import com.google.android.exoplayer2.ui.PlayerControlView;
import com.google.android.exoplayer2.ui.PlayerView; import com.google.android.exoplayer2.ui.PlayerView;
import com.google.android.gms.cast.framework.CastContext; import com.google.android.gms.cast.framework.CastContext;
...@@ -58,13 +54,12 @@ import java.util.ArrayList; ...@@ -58,13 +54,12 @@ import java.util.ArrayList;
private final PlayerView localPlayerView; private final PlayerView localPlayerView;
private final PlayerControlView castControlView; private final PlayerControlView castControlView;
private final DefaultTrackSelector trackSelector; private final Player localPlayer;
private final SimpleExoPlayer exoPlayer;
private final CastPlayer castPlayer; private final CastPlayer castPlayer;
private final ArrayList<MediaItem> mediaQueue; private final ArrayList<MediaItem> mediaQueue;
private final Listener listener; private final Listener listener;
private TrackGroupArray lastSeenTrackGroupArray; private TracksInfo lastSeenTrackGroupInfo;
private int currentItemIndex; private int currentItemIndex;
private Player currentPlayer; private Player currentPlayer;
...@@ -89,17 +84,16 @@ import java.util.ArrayList; ...@@ -89,17 +84,16 @@ import java.util.ArrayList;
mediaQueue = new ArrayList<>(); mediaQueue = new ArrayList<>();
currentItemIndex = C.INDEX_UNSET; currentItemIndex = C.INDEX_UNSET;
trackSelector = new DefaultTrackSelector(context); localPlayer = new ExoPlayer.Builder(context).build();
exoPlayer = new ExoPlayer.Builder(context).setTrackSelector(trackSelector).build(); localPlayer.addListener(this);
exoPlayer.addListener(this); localPlayerView.setPlayer(localPlayer);
localPlayerView.setPlayer(exoPlayer);
castPlayer = new CastPlayer(castContext); castPlayer = new CastPlayer(castContext);
castPlayer.addListener(this); castPlayer.addListener(this);
castPlayer.setSessionAvailabilityListener(this); castPlayer.setSessionAvailabilityListener(this);
castControlView.setPlayer(castPlayer); castControlView.setPlayer(castPlayer);
setCurrentPlayer(castPlayer.isCastSessionAvailable() ? castPlayer : exoPlayer); setCurrentPlayer(castPlayer.isCastSessionAvailable() ? castPlayer : localPlayer);
} }
// Queue manipulation methods. // Queue manipulation methods.
...@@ -200,7 +194,7 @@ import java.util.ArrayList; ...@@ -200,7 +194,7 @@ import java.util.ArrayList;
* @return Whether the event was handled by the target view. * @return Whether the event was handled by the target view.
*/ */
public boolean dispatchKeyEvent(KeyEvent event) { public boolean dispatchKeyEvent(KeyEvent event) {
if (currentPlayer == exoPlayer) { if (currentPlayer == localPlayer) {
return localPlayerView.dispatchKeyEvent(event); return localPlayerView.dispatchKeyEvent(event);
} else /* currentPlayer == castPlayer */ { } else /* currentPlayer == castPlayer */ {
return castControlView.dispatchKeyEvent(event); return castControlView.dispatchKeyEvent(event);
...@@ -214,7 +208,7 @@ import java.util.ArrayList; ...@@ -214,7 +208,7 @@ import java.util.ArrayList;
castPlayer.setSessionAvailabilityListener(null); castPlayer.setSessionAvailabilityListener(null);
castPlayer.release(); castPlayer.release();
localPlayerView.setPlayer(null); localPlayerView.setPlayer(null);
exoPlayer.release(); localPlayer.release();
} }
// Player.Listener implementation. // Player.Listener implementation.
...@@ -238,24 +232,17 @@ import java.util.ArrayList; ...@@ -238,24 +232,17 @@ import java.util.ArrayList;
} }
@Override @Override
public void onTracksChanged( public void onTracksInfoChanged(TracksInfo tracksInfo) {
@NonNull TrackGroupArray trackGroups, @NonNull TrackSelectionArray trackSelections) { if (currentPlayer != localPlayer || tracksInfo == lastSeenTrackGroupInfo) {
if (currentPlayer == exoPlayer && trackGroups != lastSeenTrackGroupArray) { return;
@Nullable }
MappingTrackSelector.MappedTrackInfo mappedTrackInfo = if (!tracksInfo.isTypeSupportedOrEmpty(C.TRACK_TYPE_VIDEO)) {
trackSelector.getCurrentMappedTrackInfo(); listener.onUnsupportedTrack(C.TRACK_TYPE_VIDEO);
if (mappedTrackInfo != null) { }
if (mappedTrackInfo.getTypeSupport(C.TRACK_TYPE_VIDEO) if (!tracksInfo.isTypeSupportedOrEmpty(C.TRACK_TYPE_AUDIO)) {
== MappingTrackSelector.MappedTrackInfo.RENDERER_SUPPORT_UNSUPPORTED_TRACKS) { listener.onUnsupportedTrack(C.TRACK_TYPE_AUDIO);
listener.onUnsupportedTrack(C.TRACK_TYPE_VIDEO);
}
if (mappedTrackInfo.getTypeSupport(C.TRACK_TYPE_AUDIO)
== MappingTrackSelector.MappedTrackInfo.RENDERER_SUPPORT_UNSUPPORTED_TRACKS) {
listener.onUnsupportedTrack(C.TRACK_TYPE_AUDIO);
}
}
lastSeenTrackGroupArray = trackGroups;
} }
lastSeenTrackGroupInfo = tracksInfo;
} }
// CastPlayer.SessionAvailabilityListener implementation. // CastPlayer.SessionAvailabilityListener implementation.
...@@ -267,7 +254,7 @@ import java.util.ArrayList; ...@@ -267,7 +254,7 @@ import java.util.ArrayList;
@Override @Override
public void onCastSessionUnavailable() { public void onCastSessionUnavailable() {
setCurrentPlayer(exoPlayer); setCurrentPlayer(localPlayer);
} }
// Internal methods. // Internal methods.
...@@ -286,7 +273,7 @@ import java.util.ArrayList; ...@@ -286,7 +273,7 @@ import java.util.ArrayList;
} }
// View management. // View management.
if (currentPlayer == exoPlayer) { if (currentPlayer == localPlayer) {
localPlayerView.setVisibility(View.VISIBLE); localPlayerView.setVisibility(View.VISIBLE);
castControlView.hide(); castControlView.hide();
} else /* currentPlayer == castPlayer */ { } else /* currentPlayer == castPlayer */ {
......
...@@ -38,6 +38,7 @@ import com.google.android.exoplayer2.PlaybackException; ...@@ -38,6 +38,7 @@ 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.SimpleExoPlayer; import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.TracksInfo;
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;
...@@ -46,11 +47,8 @@ import com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryExcep ...@@ -46,11 +47,8 @@ import com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryExcep
import com.google.android.exoplayer2.offline.DownloadRequest; import com.google.android.exoplayer2.offline.DownloadRequest;
import com.google.android.exoplayer2.source.DefaultMediaSourceFactory; import com.google.android.exoplayer2.source.DefaultMediaSourceFactory;
import com.google.android.exoplayer2.source.MediaSourceFactory; import com.google.android.exoplayer2.source.MediaSourceFactory;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.source.ads.AdsLoader; import com.google.android.exoplayer2.source.ads.AdsLoader;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.MappingTrackSelector.MappedTrackInfo;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import com.google.android.exoplayer2.ui.StyledPlayerControlView; import com.google.android.exoplayer2.ui.StyledPlayerControlView;
import com.google.android.exoplayer2.ui.StyledPlayerView; import com.google.android.exoplayer2.ui.StyledPlayerView;
import com.google.android.exoplayer2.upstream.DataSource; import com.google.android.exoplayer2.upstream.DataSource;
...@@ -69,7 +67,7 @@ public class PlayerActivity extends AppCompatActivity ...@@ -69,7 +67,7 @@ public class PlayerActivity extends AppCompatActivity
// Saved instance state keys. // Saved instance state keys.
private static final String KEY_TRACK_SELECTOR_PARAMETERS = "track_selector_parameters"; private static final String KEY_TRACK_SELECTION_PARAMETERS = "track_selection_parameters";
private static final String KEY_WINDOW = "window"; private static final String KEY_WINDOW = "window";
private static final String KEY_POSITION = "position"; private static final String KEY_POSITION = "position";
private static final String KEY_AUTO_PLAY = "auto_play"; private static final String KEY_AUTO_PLAY = "auto_play";
...@@ -84,9 +82,9 @@ public class PlayerActivity extends AppCompatActivity ...@@ -84,9 +82,9 @@ public class PlayerActivity extends AppCompatActivity
private DataSource.Factory dataSourceFactory; private DataSource.Factory dataSourceFactory;
private List<MediaItem> mediaItems; private List<MediaItem> mediaItems;
private DefaultTrackSelector trackSelector; private DefaultTrackSelector trackSelector;
private DefaultTrackSelector.Parameters trackSelectorParameters; private DefaultTrackSelector.Parameters trackSelectionParameters;
private DebugTextViewHelper debugViewHelper; private DebugTextViewHelper debugViewHelper;
private TrackGroupArray lastSeenTrackGroupArray; private TracksInfo lastSeenTracksInfo;
private boolean startAutoPlay; private boolean startAutoPlay;
private int startWindow; private int startWindow;
private long startPosition; private long startPosition;
...@@ -114,16 +112,16 @@ public class PlayerActivity extends AppCompatActivity ...@@ -114,16 +112,16 @@ public class PlayerActivity extends AppCompatActivity
playerView.requestFocus(); playerView.requestFocus();
if (savedInstanceState != null) { if (savedInstanceState != null) {
trackSelectorParameters = // Restore as DefaultTrackSelector.Parameters in case ExoPlayer specific parameters were set.
trackSelectionParameters =
DefaultTrackSelector.Parameters.CREATOR.fromBundle( DefaultTrackSelector.Parameters.CREATOR.fromBundle(
savedInstanceState.getBundle(KEY_TRACK_SELECTOR_PARAMETERS)); savedInstanceState.getBundle(KEY_TRACK_SELECTION_PARAMETERS));
startAutoPlay = savedInstanceState.getBoolean(KEY_AUTO_PLAY); startAutoPlay = savedInstanceState.getBoolean(KEY_AUTO_PLAY);
startWindow = savedInstanceState.getInt(KEY_WINDOW); startWindow = savedInstanceState.getInt(KEY_WINDOW);
startPosition = savedInstanceState.getLong(KEY_POSITION); startPosition = savedInstanceState.getLong(KEY_POSITION);
} else { } else {
DefaultTrackSelector.ParametersBuilder builder = trackSelectionParameters =
new DefaultTrackSelector.ParametersBuilder(/* context= */ this); new DefaultTrackSelector.ParametersBuilder(/* context= */ this).build();
trackSelectorParameters = builder.build();
clearStartPosition(); clearStartPosition();
} }
} }
...@@ -209,7 +207,7 @@ public class PlayerActivity extends AppCompatActivity ...@@ -209,7 +207,7 @@ public class PlayerActivity extends AppCompatActivity
super.onSaveInstanceState(outState); super.onSaveInstanceState(outState);
updateTrackSelectorParameters(); updateTrackSelectorParameters();
updateStartPosition(); updateStartPosition();
outState.putBundle(KEY_TRACK_SELECTOR_PARAMETERS, trackSelectorParameters.toBundle()); outState.putBundle(KEY_TRACK_SELECTION_PARAMETERS, trackSelectionParameters.toBundle());
outState.putBoolean(KEY_AUTO_PLAY, startAutoPlay); outState.putBoolean(KEY_AUTO_PLAY, startAutoPlay);
outState.putInt(KEY_WINDOW, startWindow); outState.putInt(KEY_WINDOW, startWindow);
outState.putLong(KEY_POSITION, startPosition); outState.putLong(KEY_POSITION, startPosition);
...@@ -272,13 +270,13 @@ public class PlayerActivity extends AppCompatActivity ...@@ -272,13 +270,13 @@ public class PlayerActivity extends AppCompatActivity
.setAdViewProvider(playerView); .setAdViewProvider(playerView);
trackSelector = new DefaultTrackSelector(/* context= */ this); trackSelector = new DefaultTrackSelector(/* context= */ this);
trackSelector.setParameters(trackSelectorParameters); lastSeenTracksInfo = TracksInfo.EMPTY;
lastSeenTrackGroupArray = null;
player = player =
new ExoPlayer.Builder(/* context= */ this, renderersFactory) new ExoPlayer.Builder(/* context= */ this, renderersFactory)
.setMediaSourceFactory(mediaSourceFactory) .setMediaSourceFactory(mediaSourceFactory)
.setTrackSelector(trackSelector) .setTrackSelector(trackSelector)
.build(); .build();
player.setTrackSelectionParameters(trackSelectionParameters);
player.addListener(new PlayerEventListener()); player.addListener(new PlayerEventListener());
player.addAnalyticsListener(new EventLogger(trackSelector)); player.addAnalyticsListener(new EventLogger(trackSelector));
player.setAudioAttributes(AudioAttributes.DEFAULT, /* handleAudioFocus= */ true); player.setAudioAttributes(AudioAttributes.DEFAULT, /* handleAudioFocus= */ true);
...@@ -361,7 +359,6 @@ public class PlayerActivity extends AppCompatActivity ...@@ -361,7 +359,6 @@ public class PlayerActivity extends AppCompatActivity
player.release(); player.release();
player = null; player = null;
mediaItems = Collections.emptyList(); mediaItems = Collections.emptyList();
trackSelector = null;
} }
if (adsLoader != null) { if (adsLoader != null) {
adsLoader.setPlayer(null); adsLoader.setPlayer(null);
...@@ -377,8 +374,11 @@ public class PlayerActivity extends AppCompatActivity ...@@ -377,8 +374,11 @@ public class PlayerActivity extends AppCompatActivity
} }
private void updateTrackSelectorParameters() { private void updateTrackSelectorParameters() {
if (trackSelector != null) { if (player != null) {
trackSelectorParameters = trackSelector.getParameters(); // Until the demo app is fully migrated to TrackSelectionParameters, rely on ExoPlayer to use
// DefaultTrackSelector by default.
trackSelectionParameters =
(DefaultTrackSelector.Parameters) player.getTrackSelectionParameters();
} }
} }
...@@ -438,23 +438,18 @@ public class PlayerActivity extends AppCompatActivity ...@@ -438,23 +438,18 @@ public class PlayerActivity extends AppCompatActivity
@Override @Override
@SuppressWarnings("ReferenceEquality") @SuppressWarnings("ReferenceEquality")
public void onTracksChanged( public void onTracksInfoChanged(TracksInfo tracksInfo) {
@NonNull TrackGroupArray trackGroups, @NonNull TrackSelectionArray trackSelections) {
updateButtonVisibility(); updateButtonVisibility();
if (trackGroups != lastSeenTrackGroupArray) { if (tracksInfo == lastSeenTracksInfo) {
MappedTrackInfo mappedTrackInfo = trackSelector.getCurrentMappedTrackInfo(); return;
if (mappedTrackInfo != null) { }
if (mappedTrackInfo.getTypeSupport(C.TRACK_TYPE_VIDEO) if (!tracksInfo.isTypeSupportedOrEmpty(C.TRACK_TYPE_VIDEO)) {
== MappedTrackInfo.RENDERER_SUPPORT_UNSUPPORTED_TRACKS) { showToast(R.string.error_unsupported_video);
showToast(R.string.error_unsupported_video); }
} if (!tracksInfo.isTypeSupportedOrEmpty(C.TRACK_TYPE_AUDIO)) {
if (mappedTrackInfo.getTypeSupport(C.TRACK_TYPE_AUDIO) showToast(R.string.error_unsupported_audio);
== MappedTrackInfo.RENDERER_SUPPORT_UNSUPPORTED_TRACKS) {
showToast(R.string.error_unsupported_audio);
}
}
lastSeenTrackGroupArray = trackGroups;
} }
lastSeenTracksInfo = tracksInfo;
} }
} }
......
...@@ -58,8 +58,6 @@ import com.google.android.exoplayer2.Timeline; ...@@ -58,8 +58,6 @@ import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.source.ads.AdPlaybackState; import com.google.android.exoplayer2.source.ads.AdPlaybackState;
import com.google.android.exoplayer2.source.ads.AdsLoader.EventListener; import com.google.android.exoplayer2.source.ads.AdsLoader.EventListener;
import com.google.android.exoplayer2.source.ads.AdsMediaSource.AdLoadException; import com.google.android.exoplayer2.source.ads.AdsMediaSource.AdLoadException;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import com.google.android.exoplayer2.trackselection.TrackSelectionUtil;
import com.google.android.exoplayer2.ui.AdOverlayInfo; import com.google.android.exoplayer2.ui.AdOverlayInfo;
import com.google.android.exoplayer2.ui.AdViewProvider; import com.google.android.exoplayer2.ui.AdViewProvider;
import com.google.android.exoplayer2.upstream.DataSpec; import com.google.android.exoplayer2.upstream.DataSpec;
...@@ -706,8 +704,7 @@ import java.util.Map; ...@@ -706,8 +704,7 @@ import java.util.Map;
} }
// Check for a selected track using an audio renderer. // Check for a selected track using an audio renderer.
TrackSelectionArray trackSelections = player.getCurrentTrackSelections(); return player.getCurrentTracksInfo().isTypeSelected(C.TRACK_TYPE_AUDIO) ? 100 : 0;
return TrackSelectionUtil.hasTrackOfType(trackSelections, C.TRACK_TYPE_AUDIO) ? 100 : 0;
} }
private void handleAdEvent(AdEvent adEvent) { private void handleAdEvent(AdEvent adEvent) {
......
...@@ -112,10 +112,13 @@ public final class TracksInfo implements Bundleable { ...@@ -112,10 +112,13 @@ public final class TracksInfo implements Bundleable {
/** /**
* Returns if a track in a {@link TrackGroup} is selected for playback. * Returns if a track in a {@link TrackGroup} is selected for playback.
* *
* <p>Multiple tracks of a track group may be selected, in which case the the active one * <p>Multiple tracks of a track group may be selected. This is common in adaptive streaming,
* (currently playing) is undefined. This is common in adaptive streaming, where multiple tracks * where multiple tracks of different quality are selected and the player switches between them
* of different quality are selected and the active one changes depending on the network and the * depending on the network and the {@link TrackSelectionParameters}.
* {@link TrackSelectionParameters}. *
* <p>While this class doesn't provide which selected track is currently playing, some player
* implementations have ways of getting such information. For example ExoPlayer provides this
* information in {@code ExoTrackSelection.getSelectedFormat}.
* *
* @param trackIndex The index of the track in the {@link TrackGroup}. * @param trackIndex The index of the track in the {@link TrackGroup}.
* @return true if the track is selected, false otherwise. * @return true if the track is selected, false otherwise.
......
...@@ -27,6 +27,7 @@ import com.google.android.exoplayer2.PlaybackException; ...@@ -27,6 +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.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;
...@@ -34,9 +35,7 @@ import com.google.android.exoplayer2.analytics.PlaybackStats.PlaybackState; ...@@ -34,9 +35,7 @@ import com.google.android.exoplayer2.analytics.PlaybackStats.PlaybackState;
import com.google.android.exoplayer2.source.LoadEventInfo; import com.google.android.exoplayer2.source.LoadEventInfo;
import com.google.android.exoplayer2.source.MediaLoadData; import com.google.android.exoplayer2.source.MediaLoadData;
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId; import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
import com.google.android.exoplayer2.trackselection.TrackSelection;
import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import com.google.android.exoplayer2.video.VideoSize; import com.google.android.exoplayer2.video.VideoSize;
import java.io.IOException; import java.io.IOException;
...@@ -523,23 +522,11 @@ public final class PlaybackStatsListener ...@@ -523,23 +522,11 @@ public final class PlaybackStatsListener
hasFatalError = false; hasFatalError = false;
} }
if (isForeground && !isInterruptedByAd) { if (isForeground && !isInterruptedByAd) {
boolean videoEnabled = false; TracksInfo currentTracksInfo = player.getCurrentTracksInfo();
boolean audioEnabled = false; if (!currentTracksInfo.isTypeSelected(C.TRACK_TYPE_VIDEO)) {
for (TrackSelection trackSelection : player.getCurrentTrackSelections().getAll()) {
if (trackSelection != null && trackSelection.length() > 0) {
@C.TrackType
int trackType = MimeTypes.getTrackType(trackSelection.getFormat(0).sampleMimeType);
if (trackType == C.TRACK_TYPE_VIDEO) {
videoEnabled = true;
} else if (trackType == C.TRACK_TYPE_AUDIO) {
audioEnabled = true;
}
}
}
if (!videoEnabled) {
maybeUpdateVideoFormat(eventTime, /* newFormat= */ null); maybeUpdateVideoFormat(eventTime, /* newFormat= */ null);
} }
if (!audioEnabled) { if (!currentTracksInfo.isTypeSelected(C.TRACK_TYPE_AUDIO)) {
maybeUpdateAudioFormat(eventTime, /* newFormat= */ null); maybeUpdateAudioFormat(eventTime, /* newFormat= */ null);
} }
} }
......
...@@ -17,12 +17,21 @@ package com.google.android.exoplayer2.trackselection; ...@@ -17,12 +17,21 @@ package com.google.android.exoplayer2.trackselection;
import android.os.SystemClock; import android.os.SystemClock;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.TracksInfo;
import com.google.android.exoplayer2.TracksInfo.TrackGroupInfo;
import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.SelectionOverride; import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.SelectionOverride;
import com.google.android.exoplayer2.trackselection.ExoTrackSelection.Definition; import com.google.android.exoplayer2.trackselection.ExoTrackSelection.Definition;
import com.google.android.exoplayer2.trackselection.TrackSelectionParameters.TrackSelectionOverride;
import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy; import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy;
import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.exoplayer2.util.MimeTypes;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import java.util.Map;
import org.checkerframework.checker.nullness.compatqual.NullableType; import org.checkerframework.checker.nullness.compatqual.NullableType;
import org.checkerframework.dataflow.qual.Pure;
/** Track selection related utility methods. */ /** Track selection related utility methods. */
public final class TrackSelectionUtil { public final class TrackSelectionUtil {
...@@ -101,22 +110,6 @@ public final class TrackSelectionUtil { ...@@ -101,22 +110,6 @@ public final class TrackSelectionUtil {
return builder.build(); return builder.build();
} }
/** Returns if a {@link TrackSelectionArray} has at least one track of the given type. */
public static boolean hasTrackOfType(TrackSelectionArray trackSelections, int trackType) {
for (int i = 0; i < trackSelections.length; i++) {
@Nullable TrackSelection trackSelection = trackSelections.get(i);
if (trackSelection == null) {
continue;
}
for (int j = 0; j < trackSelection.length(); j++) {
if (MimeTypes.getTrackType(trackSelection.getFormat(j).sampleMimeType) == trackType) {
return true;
}
}
}
return false;
}
/** /**
* Returns the {@link LoadErrorHandlingPolicy.FallbackOptions} with the tracks of the given {@link * Returns the {@link LoadErrorHandlingPolicy.FallbackOptions} with the tracks of the given {@link
* ExoTrackSelection} and with a single location option indicating that there are no alternative * ExoTrackSelection} and with a single location option indicating that there are no alternative
...@@ -141,4 +134,67 @@ public final class TrackSelectionUtil { ...@@ -141,4 +134,67 @@ public final class TrackSelectionUtil {
numberOfTracks, numberOfTracks,
numberOfExcludedTracks); numberOfExcludedTracks);
} }
/**
* Forces tracks in a {@link TrackGroup} to be the only ones selected for a {@link C.TrackType}.
* No other tracks of that type will be selectable. If the forced tracks are not supported, then
* no tracks of that type will be selected.
*
* @param trackSelectionOverrides The current {@link TrackSelectionOverride overrides}.
* @param tracksInfo The current {@link TracksInfo}.
* @param forcedTrackGroupIndex The index of the {@link TrackGroup} in {@code tracksInfo} that
* should have its track selected.
* @param forcedTrackSelectionOverride The tracks to force selection of.
* @return The updated {@link TrackSelectionOverride overrides}.
*/
@Pure
public static ImmutableMap<TrackGroup, TrackSelectionOverride> forceTrackSelection(
ImmutableMap<TrackGroup, TrackSelectionOverride> trackSelectionOverrides,
TracksInfo tracksInfo,
int forcedTrackGroupIndex,
TrackSelectionOverride forcedTrackSelectionOverride) {
@C.TrackType
int trackType = tracksInfo.getTrackGroupInfos().get(forcedTrackGroupIndex).getTrackType();
ImmutableMap.Builder<TrackGroup, TrackSelectionOverride> overridesBuilder =
new ImmutableMap.Builder<>();
// Maintain overrides for the other track types.
for (Map.Entry<TrackGroup, TrackSelectionOverride> entry : trackSelectionOverrides.entrySet()) {
if (MimeTypes.getTrackType(entry.getKey().getFormat(0).sampleMimeType) != trackType) {
overridesBuilder.put(entry);
}
}
ImmutableList<TrackGroupInfo> trackGroupInfos = tracksInfo.getTrackGroupInfos();
for (int i = 0; i < trackGroupInfos.size(); i++) {
TrackGroup trackGroup = trackGroupInfos.get(i).getTrackGroup();
if (i == forcedTrackGroupIndex) {
overridesBuilder.put(trackGroup, forcedTrackSelectionOverride);
} else {
overridesBuilder.put(trackGroup, TrackSelectionOverride.DISABLE);
}
}
return overridesBuilder.build();
}
/**
* Removes all {@link TrackSelectionOverride overrides} associated with {@link TrackGroup
* TrackGroups} of type {@code trackType}.
*
* @param trackType The {@link C.TrackType} of all overrides to remove.
* @param trackSelectionOverrides The current {@link TrackSelectionOverride overrides}.
* @return The updated {@link TrackSelectionOverride overrides}.
*/
@Pure
public static ImmutableMap<TrackGroup, TrackSelectionOverride>
clearTrackSelectionOverridesForType(
@C.TrackType int trackType,
ImmutableMap<TrackGroup, TrackSelectionOverride> trackSelectionOverrides) {
ImmutableMap.Builder<TrackGroup, TrackSelectionOverride> overridesBuilder =
ImmutableMap.builder();
for (Map.Entry<TrackGroup, TrackSelectionOverride> entry : trackSelectionOverrides.entrySet()) {
if (MimeTypes.getTrackType(entry.getKey().getFormat(0).sampleMimeType) != trackType) {
overridesBuilder.put(entry);
}
}
return overridesBuilder.build();
}
} }
...@@ -7349,7 +7349,7 @@ public final class ExoPlayerTest { ...@@ -7349,7 +7349,7 @@ public final class ExoPlayerTest {
} }
}; };
AtomicReference<Timeline> timelineAfterError = new AtomicReference<>(); AtomicReference<Timeline> timelineAfterError = new AtomicReference<>();
AtomicReference<TrackGroupArray> trackGroupsAfterError = new AtomicReference<>(); AtomicReference<TracksInfo> trackInfosAfterError = new AtomicReference<>();
AtomicReference<TrackSelectionArray> trackSelectionsAfterError = new AtomicReference<>(); AtomicReference<TrackSelectionArray> trackSelectionsAfterError = new AtomicReference<>();
AtomicInteger windowIndexAfterError = new AtomicInteger(); AtomicInteger windowIndexAfterError = new AtomicInteger();
ActionSchedule actionSchedule = ActionSchedule actionSchedule =
...@@ -7363,7 +7363,7 @@ public final class ExoPlayerTest { ...@@ -7363,7 +7363,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());
trackGroupsAfterError.set(player.getCurrentTrackGroups()); trackInfosAfterError.set(player.getCurrentTracksInfo());
trackSelectionsAfterError.set(player.getCurrentTrackSelections()); trackSelectionsAfterError.set(player.getCurrentTrackSelections());
windowIndexAfterError.set(player.getCurrentWindowIndex()); windowIndexAfterError.set(player.getCurrentWindowIndex());
} }
...@@ -7393,8 +7393,8 @@ public final class ExoPlayerTest { ...@@ -7393,8 +7393,8 @@ public final class ExoPlayerTest {
assertThat(timelineAfterError.get().getWindowCount()).isEqualTo(1); assertThat(timelineAfterError.get().getWindowCount()).isEqualTo(1);
assertThat(windowIndexAfterError.get()).isEqualTo(0); assertThat(windowIndexAfterError.get()).isEqualTo(0);
assertThat(trackGroupsAfterError.get().length).isEqualTo(1); assertThat(trackInfosAfterError.get().getTrackGroupInfos()).hasSize(1);
assertThat(trackGroupsAfterError.get().get(0).getFormat(0)) assertThat(trackInfosAfterError.get().getTrackGroupInfos().get(0).getTrackGroup().getFormat(0))
.isEqualTo(ExoPlayerTestRunner.AUDIO_FORMAT); .isEqualTo(ExoPlayerTestRunner.AUDIO_FORMAT);
assertThat(trackSelectionsAfterError.get().get(0)).isNull(); // Video renderer. assertThat(trackSelectionsAfterError.get().get(0)).isNull(); // Video renderer.
assertThat(trackSelectionsAfterError.get().get(1)).isNotNull(); // Audio renderer. assertThat(trackSelectionsAfterError.get().get(1)).isNotNull(); // Audio renderer.
......
...@@ -47,7 +47,6 @@ import androidx.annotation.RequiresApi; ...@@ -47,7 +47,6 @@ import androidx.annotation.RequiresApi;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ControlDispatcher; import com.google.android.exoplayer2.ControlDispatcher;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.ForwardingPlayer; import com.google.android.exoplayer2.ForwardingPlayer;
import com.google.android.exoplayer2.MediaMetadata; import com.google.android.exoplayer2.MediaMetadata;
import com.google.android.exoplayer2.PlaybackException; import com.google.android.exoplayer2.PlaybackException;
...@@ -57,12 +56,9 @@ import com.google.android.exoplayer2.Timeline; ...@@ -57,12 +56,9 @@ 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.TracksInfo;
import com.google.android.exoplayer2.text.Cue; import com.google.android.exoplayer2.text.Cue;
import com.google.android.exoplayer2.trackselection.TrackSelection;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
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;
import com.google.android.exoplayer2.util.ErrorMessageProvider; import com.google.android.exoplayer2.util.ErrorMessageProvider;
import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.RepeatModeUtil; import com.google.android.exoplayer2.util.RepeatModeUtil;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import com.google.android.exoplayer2.video.VideoSize; import com.google.android.exoplayer2.video.VideoSize;
...@@ -1256,7 +1252,9 @@ public class PlayerView extends FrameLayout implements AdViewProvider { ...@@ -1256,7 +1252,9 @@ public class PlayerView 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.getCurrentTrackGroups().isEmpty()) { if (player == null
|| !player.isCommandAvailable(Player.COMMAND_GET_TRACK_INFOS)
|| player.getCurrentTracksInfo().getTrackGroupInfos().isEmpty()) {
if (!keepContentOnPlayerReset) { if (!keepContentOnPlayerReset) {
hideArtwork(); hideArtwork();
closeShutter(); closeShutter();
...@@ -1268,21 +1266,11 @@ public class PlayerView extends FrameLayout implements AdViewProvider { ...@@ -1268,21 +1266,11 @@ 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)) {
TrackSelectionArray trackSelections = player.getCurrentTrackSelections(); // Video enabled, so artwork must be hidden. If the shutter is closed, it will be opened
for (int i = 0; i < trackSelections.length; i++) { // in onRenderedFirstFrame().
@Nullable TrackSelection trackSelection = trackSelections.get(i); hideArtwork();
if (trackSelection != null) { return;
for (int j = 0; j < trackSelection.length(); j++) {
Format format = trackSelection.getFormat(j);
if (MimeTypes.getTrackType(format.sampleMimeType) == C.TRACK_TYPE_VIDEO) {
// Video enabled, so artwork must be hidden. If the shutter is closed, it will be opened
// in onRenderedFirstFrame().
hideArtwork();
return;
}
}
}
} }
// Video disabled so the shutter must be closed. // Video disabled so the shutter must be closed.
...@@ -1518,7 +1506,7 @@ public class PlayerView extends FrameLayout implements AdViewProvider { ...@@ -1518,7 +1506,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.getCurrentTrackGroups().isEmpty()) { } else if (!player.getCurrentTracksInfo().getTrackGroupInfos().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) {
......
...@@ -48,7 +48,6 @@ import androidx.annotation.RequiresApi; ...@@ -48,7 +48,6 @@ import androidx.annotation.RequiresApi;
import androidx.core.content.ContextCompat; import androidx.core.content.ContextCompat;
import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ControlDispatcher; import com.google.android.exoplayer2.ControlDispatcher;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.ForwardingPlayer; import com.google.android.exoplayer2.ForwardingPlayer;
import com.google.android.exoplayer2.MediaMetadata; import com.google.android.exoplayer2.MediaMetadata;
import com.google.android.exoplayer2.PlaybackException; import com.google.android.exoplayer2.PlaybackException;
...@@ -58,12 +57,9 @@ import com.google.android.exoplayer2.Timeline; ...@@ -58,12 +57,9 @@ 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.TracksInfo;
import com.google.android.exoplayer2.text.Cue; import com.google.android.exoplayer2.text.Cue;
import com.google.android.exoplayer2.trackselection.TrackSelection;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
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;
import com.google.android.exoplayer2.util.ErrorMessageProvider; import com.google.android.exoplayer2.util.ErrorMessageProvider;
import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.RepeatModeUtil; import com.google.android.exoplayer2.util.RepeatModeUtil;
import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.util.Util;
import com.google.android.exoplayer2.video.VideoSize; import com.google.android.exoplayer2.video.VideoSize;
...@@ -1296,7 +1292,7 @@ public class StyledPlayerView extends FrameLayout implements AdViewProvider { ...@@ -1296,7 +1292,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.getCurrentTrackGroups().isEmpty()) { if (player == null || player.getCurrentTracksInfo().getTrackGroupInfos().isEmpty()) {
if (!keepContentOnPlayerReset) { if (!keepContentOnPlayerReset) {
hideArtwork(); hideArtwork();
closeShutter(); closeShutter();
...@@ -1309,20 +1305,11 @@ public class StyledPlayerView extends FrameLayout implements AdViewProvider { ...@@ -1309,20 +1305,11 @@ public class StyledPlayerView extends FrameLayout implements AdViewProvider {
closeShutter(); closeShutter();
} }
TrackSelectionArray trackSelections = player.getCurrentTrackSelections(); if (player.getCurrentTracksInfo().isTypeSelected(C.TRACK_TYPE_VIDEO)) {
for (int i = 0; i < trackSelections.length; i++) { // Video enabled, so artwork must be hidden. If the shutter is closed, it will be opened
@Nullable TrackSelection trackSelection = trackSelections.get(i); // in onRenderedFirstFrame().
if (trackSelection != null) { hideArtwork();
for (int j = 0; j < trackSelection.length(); j++) { return;
Format format = trackSelection.getFormat(j);
if (MimeTypes.getTrackType(format.sampleMimeType) == C.TRACK_TYPE_VIDEO) {
// Video enabled, so artwork must be hidden. If the shutter is closed, it will be opened
// in onRenderedFirstFrame().
hideArtwork();
return;
}
}
}
} }
// Video disabled so the shutter must be closed. // Video disabled so the shutter must be closed.
...@@ -1558,7 +1545,7 @@ public class StyledPlayerView extends FrameLayout implements AdViewProvider { ...@@ -1558,7 +1545,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.getCurrentTrackGroups().isEmpty()) { } else if (!player.getCurrentTracksInfo().getTrackGroupInfos().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) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment