diff --git a/demos/cast/src/main/java/com/google/android/exoplayer2/castdemo/PlayerManager.java b/demos/cast/src/main/java/com/google/android/exoplayer2/castdemo/PlayerManager.java index e6a55b1ce5..4853229c50 100644 --- a/demos/cast/src/main/java/com/google/android/exoplayer2/castdemo/PlayerManager.java +++ b/demos/cast/src/main/java/com/google/android/exoplayer2/castdemo/PlayerManager.java @@ -19,7 +19,6 @@ import android.content.Context; import android.view.KeyEvent; import android.view.View; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.MediaItem; @@ -28,12 +27,9 @@ import com.google.android.exoplayer2.Player.DiscontinuityReason; import com.google.android.exoplayer2.Player.TimelineChangeReason; import com.google.android.exoplayer2.SimpleExoPlayer; 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.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.PlayerView; import com.google.android.gms.cast.framework.CastContext; @@ -58,13 +54,12 @@ import java.util.ArrayList; private final PlayerView localPlayerView; private final PlayerControlView castControlView; - private final DefaultTrackSelector trackSelector; - private final SimpleExoPlayer exoPlayer; + private final Player localPlayer; private final CastPlayer castPlayer; private final ArrayList mediaQueue; private final Listener listener; - private TrackGroupArray lastSeenTrackGroupArray; + private TracksInfo lastSeenTrackGroupInfo; private int currentItemIndex; private Player currentPlayer; @@ -89,17 +84,16 @@ import java.util.ArrayList; mediaQueue = new ArrayList<>(); currentItemIndex = C.INDEX_UNSET; - trackSelector = new DefaultTrackSelector(context); - exoPlayer = new ExoPlayer.Builder(context).setTrackSelector(trackSelector).build(); - exoPlayer.addListener(this); - localPlayerView.setPlayer(exoPlayer); + localPlayer = new ExoPlayer.Builder(context).build(); + localPlayer.addListener(this); + localPlayerView.setPlayer(localPlayer); castPlayer = new CastPlayer(castContext); castPlayer.addListener(this); castPlayer.setSessionAvailabilityListener(this); castControlView.setPlayer(castPlayer); - setCurrentPlayer(castPlayer.isCastSessionAvailable() ? castPlayer : exoPlayer); + setCurrentPlayer(castPlayer.isCastSessionAvailable() ? castPlayer : localPlayer); } // Queue manipulation methods. @@ -200,7 +194,7 @@ import java.util.ArrayList; * @return Whether the event was handled by the target view. */ public boolean dispatchKeyEvent(KeyEvent event) { - if (currentPlayer == exoPlayer) { + if (currentPlayer == localPlayer) { return localPlayerView.dispatchKeyEvent(event); } else /* currentPlayer == castPlayer */ { return castControlView.dispatchKeyEvent(event); @@ -214,7 +208,7 @@ import java.util.ArrayList; castPlayer.setSessionAvailabilityListener(null); castPlayer.release(); localPlayerView.setPlayer(null); - exoPlayer.release(); + localPlayer.release(); } // Player.Listener implementation. @@ -238,24 +232,17 @@ import java.util.ArrayList; } @Override - public void onTracksChanged( - @NonNull TrackGroupArray trackGroups, @NonNull TrackSelectionArray trackSelections) { - if (currentPlayer == exoPlayer && trackGroups != lastSeenTrackGroupArray) { - @Nullable - MappingTrackSelector.MappedTrackInfo mappedTrackInfo = - trackSelector.getCurrentMappedTrackInfo(); - if (mappedTrackInfo != null) { - if (mappedTrackInfo.getTypeSupport(C.TRACK_TYPE_VIDEO) - == MappingTrackSelector.MappedTrackInfo.RENDERER_SUPPORT_UNSUPPORTED_TRACKS) { - 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; + public void onTracksInfoChanged(TracksInfo tracksInfo) { + if (currentPlayer != localPlayer || tracksInfo == lastSeenTrackGroupInfo) { + return; } + if (!tracksInfo.isTypeSupportedOrEmpty(C.TRACK_TYPE_VIDEO)) { + listener.onUnsupportedTrack(C.TRACK_TYPE_VIDEO); + } + if (!tracksInfo.isTypeSupportedOrEmpty(C.TRACK_TYPE_AUDIO)) { + listener.onUnsupportedTrack(C.TRACK_TYPE_AUDIO); + } + lastSeenTrackGroupInfo = tracksInfo; } // CastPlayer.SessionAvailabilityListener implementation. @@ -267,7 +254,7 @@ import java.util.ArrayList; @Override public void onCastSessionUnavailable() { - setCurrentPlayer(exoPlayer); + setCurrentPlayer(localPlayer); } // Internal methods. @@ -286,7 +273,7 @@ import java.util.ArrayList; } // View management. - if (currentPlayer == exoPlayer) { + if (currentPlayer == localPlayer) { localPlayerView.setVisibility(View.VISIBLE); castControlView.hide(); } else /* currentPlayer == castPlayer */ { diff --git a/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java b/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java index 5f5acea8ea..aaad17aaa8 100644 --- a/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java +++ b/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java @@ -38,6 +38,7 @@ import com.google.android.exoplayer2.PlaybackException; import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.RenderersFactory; import com.google.android.exoplayer2.SimpleExoPlayer; +import com.google.android.exoplayer2.TracksInfo; import com.google.android.exoplayer2.audio.AudioAttributes; import com.google.android.exoplayer2.drm.FrameworkMediaDrm; import com.google.android.exoplayer2.ext.ima.ImaAdsLoader; @@ -46,11 +47,8 @@ import com.google.android.exoplayer2.mediacodec.MediaCodecUtil.DecoderQueryExcep import com.google.android.exoplayer2.offline.DownloadRequest; import com.google.android.exoplayer2.source.DefaultMediaSourceFactory; 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.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.StyledPlayerView; import com.google.android.exoplayer2.upstream.DataSource; @@ -69,7 +67,7 @@ public class PlayerActivity extends AppCompatActivity // 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_POSITION = "position"; private static final String KEY_AUTO_PLAY = "auto_play"; @@ -84,9 +82,9 @@ public class PlayerActivity extends AppCompatActivity private DataSource.Factory dataSourceFactory; private List mediaItems; private DefaultTrackSelector trackSelector; - private DefaultTrackSelector.Parameters trackSelectorParameters; + private DefaultTrackSelector.Parameters trackSelectionParameters; private DebugTextViewHelper debugViewHelper; - private TrackGroupArray lastSeenTrackGroupArray; + private TracksInfo lastSeenTracksInfo; private boolean startAutoPlay; private int startWindow; private long startPosition; @@ -114,16 +112,16 @@ public class PlayerActivity extends AppCompatActivity playerView.requestFocus(); if (savedInstanceState != null) { - trackSelectorParameters = + // Restore as DefaultTrackSelector.Parameters in case ExoPlayer specific parameters were set. + trackSelectionParameters = DefaultTrackSelector.Parameters.CREATOR.fromBundle( - savedInstanceState.getBundle(KEY_TRACK_SELECTOR_PARAMETERS)); + savedInstanceState.getBundle(KEY_TRACK_SELECTION_PARAMETERS)); startAutoPlay = savedInstanceState.getBoolean(KEY_AUTO_PLAY); startWindow = savedInstanceState.getInt(KEY_WINDOW); startPosition = savedInstanceState.getLong(KEY_POSITION); } else { - DefaultTrackSelector.ParametersBuilder builder = - new DefaultTrackSelector.ParametersBuilder(/* context= */ this); - trackSelectorParameters = builder.build(); + trackSelectionParameters = + new DefaultTrackSelector.ParametersBuilder(/* context= */ this).build(); clearStartPosition(); } } @@ -209,7 +207,7 @@ public class PlayerActivity extends AppCompatActivity super.onSaveInstanceState(outState); updateTrackSelectorParameters(); updateStartPosition(); - outState.putBundle(KEY_TRACK_SELECTOR_PARAMETERS, trackSelectorParameters.toBundle()); + outState.putBundle(KEY_TRACK_SELECTION_PARAMETERS, trackSelectionParameters.toBundle()); outState.putBoolean(KEY_AUTO_PLAY, startAutoPlay); outState.putInt(KEY_WINDOW, startWindow); outState.putLong(KEY_POSITION, startPosition); @@ -272,13 +270,13 @@ public class PlayerActivity extends AppCompatActivity .setAdViewProvider(playerView); trackSelector = new DefaultTrackSelector(/* context= */ this); - trackSelector.setParameters(trackSelectorParameters); - lastSeenTrackGroupArray = null; + lastSeenTracksInfo = TracksInfo.EMPTY; player = new ExoPlayer.Builder(/* context= */ this, renderersFactory) .setMediaSourceFactory(mediaSourceFactory) .setTrackSelector(trackSelector) .build(); + player.setTrackSelectionParameters(trackSelectionParameters); player.addListener(new PlayerEventListener()); player.addAnalyticsListener(new EventLogger(trackSelector)); player.setAudioAttributes(AudioAttributes.DEFAULT, /* handleAudioFocus= */ true); @@ -361,7 +359,6 @@ public class PlayerActivity extends AppCompatActivity player.release(); player = null; mediaItems = Collections.emptyList(); - trackSelector = null; } if (adsLoader != null) { adsLoader.setPlayer(null); @@ -377,8 +374,11 @@ public class PlayerActivity extends AppCompatActivity } private void updateTrackSelectorParameters() { - if (trackSelector != null) { - trackSelectorParameters = trackSelector.getParameters(); + if (player != null) { + // 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 @Override @SuppressWarnings("ReferenceEquality") - public void onTracksChanged( - @NonNull TrackGroupArray trackGroups, @NonNull TrackSelectionArray trackSelections) { + public void onTracksInfoChanged(TracksInfo tracksInfo) { updateButtonVisibility(); - if (trackGroups != lastSeenTrackGroupArray) { - MappedTrackInfo mappedTrackInfo = trackSelector.getCurrentMappedTrackInfo(); - if (mappedTrackInfo != null) { - if (mappedTrackInfo.getTypeSupport(C.TRACK_TYPE_VIDEO) - == MappedTrackInfo.RENDERER_SUPPORT_UNSUPPORTED_TRACKS) { - showToast(R.string.error_unsupported_video); - } - if (mappedTrackInfo.getTypeSupport(C.TRACK_TYPE_AUDIO) - == MappedTrackInfo.RENDERER_SUPPORT_UNSUPPORTED_TRACKS) { - showToast(R.string.error_unsupported_audio); - } - } - lastSeenTrackGroupArray = trackGroups; + if (tracksInfo == lastSeenTracksInfo) { + return; } + if (!tracksInfo.isTypeSupportedOrEmpty(C.TRACK_TYPE_VIDEO)) { + showToast(R.string.error_unsupported_video); + } + if (!tracksInfo.isTypeSupportedOrEmpty(C.TRACK_TYPE_AUDIO)) { + showToast(R.string.error_unsupported_audio); + } + lastSeenTracksInfo = tracksInfo; } } diff --git a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/AdTagLoader.java b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/AdTagLoader.java index 0e8b246100..f0c4a199e1 100644 --- a/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/AdTagLoader.java +++ b/extensions/ima/src/main/java/com/google/android/exoplayer2/ext/ima/AdTagLoader.java @@ -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.AdsLoader.EventListener; 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.AdViewProvider; import com.google.android.exoplayer2.upstream.DataSpec; @@ -706,8 +704,7 @@ import java.util.Map; } // Check for a selected track using an audio renderer. - TrackSelectionArray trackSelections = player.getCurrentTrackSelections(); - return TrackSelectionUtil.hasTrackOfType(trackSelections, C.TRACK_TYPE_AUDIO) ? 100 : 0; + return player.getCurrentTracksInfo().isTypeSelected(C.TRACK_TYPE_AUDIO) ? 100 : 0; } private void handleAdEvent(AdEvent adEvent) { diff --git a/library/common/src/main/java/com/google/android/exoplayer2/TracksInfo.java b/library/common/src/main/java/com/google/android/exoplayer2/TracksInfo.java index 3f587ed8d0..8f723a1859 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/TracksInfo.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/TracksInfo.java @@ -112,10 +112,13 @@ public final class TracksInfo implements Bundleable { /** * Returns if a track in a {@link TrackGroup} is selected for playback. * - *

Multiple tracks of a track group may be selected, in which case the the active one - * (currently playing) is undefined. This is common in adaptive streaming, where multiple tracks - * of different quality are selected and the active one changes depending on the network and the - * {@link TrackSelectionParameters}. + *

Multiple tracks of a track group may be selected. This is common in adaptive streaming, + * where multiple tracks of different quality are selected and the player switches between them + * depending on the network and the {@link TrackSelectionParameters}. + * + *

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}. * @return true if the track is selected, false otherwise. diff --git a/library/core/src/main/java/com/google/android/exoplayer2/analytics/PlaybackStatsListener.java b/library/core/src/main/java/com/google/android/exoplayer2/analytics/PlaybackStatsListener.java index 35adc83bd6..343fa4ce76 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/analytics/PlaybackStatsListener.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/analytics/PlaybackStatsListener.java @@ -27,6 +27,7 @@ import com.google.android.exoplayer2.PlaybackException; import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Timeline; 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.EventTimeAndFormat; import com.google.android.exoplayer2.analytics.PlaybackStats.EventTimeAndPlaybackState; @@ -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.MediaLoadData; 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.MimeTypes; import com.google.android.exoplayer2.util.Util; import com.google.android.exoplayer2.video.VideoSize; import java.io.IOException; @@ -523,23 +522,11 @@ public final class PlaybackStatsListener hasFatalError = false; } if (isForeground && !isInterruptedByAd) { - boolean videoEnabled = false; - boolean audioEnabled = false; - 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) { + TracksInfo currentTracksInfo = player.getCurrentTracksInfo(); + if (!currentTracksInfo.isTypeSelected(C.TRACK_TYPE_VIDEO)) { maybeUpdateVideoFormat(eventTime, /* newFormat= */ null); } - if (!audioEnabled) { + if (!currentTracksInfo.isTypeSelected(C.TRACK_TYPE_AUDIO)) { maybeUpdateAudioFormat(eventTime, /* newFormat= */ null); } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelectionUtil.java b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelectionUtil.java index a0cc74588d..42f0ca68a0 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelectionUtil.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/trackselection/TrackSelectionUtil.java @@ -17,12 +17,21 @@ package com.google.android.exoplayer2.trackselection; import android.os.SystemClock; import androidx.annotation.Nullable; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.TracksInfo; +import com.google.android.exoplayer2.TracksInfo.TrackGroupInfo; +import com.google.android.exoplayer2.source.TrackGroup; import com.google.android.exoplayer2.source.TrackGroupArray; import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.SelectionOverride; import com.google.android.exoplayer2.trackselection.ExoTrackSelection.Definition; +import com.google.android.exoplayer2.trackselection.TrackSelectionParameters.TrackSelectionOverride; import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy; import com.google.android.exoplayer2.util.MimeTypes; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import java.util.Map; import org.checkerframework.checker.nullness.compatqual.NullableType; +import org.checkerframework.dataflow.qual.Pure; /** Track selection related utility methods. */ public final class TrackSelectionUtil { @@ -101,22 +110,6 @@ public final class TrackSelectionUtil { 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 * ExoTrackSelection} and with a single location option indicating that there are no alternative @@ -141,4 +134,67 @@ public final class TrackSelectionUtil { numberOfTracks, numberOfExcludedTracks); } + + /** + * Forces tracks in a {@link TrackGroup} to be the only ones selected for a {@link C.TrackType}. + * No other tracks of that type will be selectable. If the forced tracks are not supported, then + * no tracks of that type will be selected. + * + * @param trackSelectionOverrides The current {@link TrackSelectionOverride overrides}. + * @param tracksInfo The current {@link TracksInfo}. + * @param forcedTrackGroupIndex The index of the {@link TrackGroup} in {@code tracksInfo} that + * should have its track selected. + * @param forcedTrackSelectionOverride The tracks to force selection of. + * @return The updated {@link TrackSelectionOverride overrides}. + */ + @Pure + public static ImmutableMap forceTrackSelection( + ImmutableMap trackSelectionOverrides, + TracksInfo tracksInfo, + int forcedTrackGroupIndex, + TrackSelectionOverride forcedTrackSelectionOverride) { + @C.TrackType + int trackType = tracksInfo.getTrackGroupInfos().get(forcedTrackGroupIndex).getTrackType(); + ImmutableMap.Builder overridesBuilder = + new ImmutableMap.Builder<>(); + // Maintain overrides for the other track types. + for (Map.Entry entry : trackSelectionOverrides.entrySet()) { + if (MimeTypes.getTrackType(entry.getKey().getFormat(0).sampleMimeType) != trackType) { + overridesBuilder.put(entry); + } + } + ImmutableList trackGroupInfos = tracksInfo.getTrackGroupInfos(); + for (int i = 0; i < trackGroupInfos.size(); i++) { + TrackGroup trackGroup = trackGroupInfos.get(i).getTrackGroup(); + if (i == forcedTrackGroupIndex) { + overridesBuilder.put(trackGroup, forcedTrackSelectionOverride); + } else { + overridesBuilder.put(trackGroup, TrackSelectionOverride.DISABLE); + } + } + return overridesBuilder.build(); + } + + /** + * Removes all {@link TrackSelectionOverride overrides} associated with {@link TrackGroup + * TrackGroups} of type {@code trackType}. + * + * @param trackType The {@link C.TrackType} of all overrides to remove. + * @param trackSelectionOverrides The current {@link TrackSelectionOverride overrides}. + * @return The updated {@link TrackSelectionOverride overrides}. + */ + @Pure + public static ImmutableMap + clearTrackSelectionOverridesForType( + @C.TrackType int trackType, + ImmutableMap trackSelectionOverrides) { + ImmutableMap.Builder overridesBuilder = + ImmutableMap.builder(); + for (Map.Entry entry : trackSelectionOverrides.entrySet()) { + if (MimeTypes.getTrackType(entry.getKey().getFormat(0).sampleMimeType) != trackType) { + overridesBuilder.put(entry); + } + } + return overridesBuilder.build(); + } } diff --git a/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java b/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java index ea9df3399e..876835c906 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/ExoPlayerTest.java @@ -7349,7 +7349,7 @@ public final class ExoPlayerTest { } }; AtomicReference timelineAfterError = new AtomicReference<>(); - AtomicReference trackGroupsAfterError = new AtomicReference<>(); + AtomicReference trackInfosAfterError = new AtomicReference<>(); AtomicReference trackSelectionsAfterError = new AtomicReference<>(); AtomicInteger windowIndexAfterError = new AtomicInteger(); ActionSchedule actionSchedule = @@ -7363,7 +7363,7 @@ public final class ExoPlayerTest { @Override public void onPlayerError(EventTime eventTime, PlaybackException error) { timelineAfterError.set(player.getCurrentTimeline()); - trackGroupsAfterError.set(player.getCurrentTrackGroups()); + trackInfosAfterError.set(player.getCurrentTracksInfo()); trackSelectionsAfterError.set(player.getCurrentTrackSelections()); windowIndexAfterError.set(player.getCurrentWindowIndex()); } @@ -7393,8 +7393,8 @@ public final class ExoPlayerTest { assertThat(timelineAfterError.get().getWindowCount()).isEqualTo(1); assertThat(windowIndexAfterError.get()).isEqualTo(0); - assertThat(trackGroupsAfterError.get().length).isEqualTo(1); - assertThat(trackGroupsAfterError.get().get(0).getFormat(0)) + assertThat(trackInfosAfterError.get().getTrackGroupInfos()).hasSize(1); + assertThat(trackInfosAfterError.get().getTrackGroupInfos().get(0).getTrackGroup().getFormat(0)) .isEqualTo(ExoPlayerTestRunner.AUDIO_FORMAT); assertThat(trackSelectionsAfterError.get().get(0)).isNull(); // Video renderer. assertThat(trackSelectionsAfterError.get().get(1)).isNotNull(); // Audio renderer. diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerView.java index 79e56a4d3d..336a2e2f38 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerView.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/PlayerView.java @@ -47,7 +47,6 @@ import androidx.annotation.RequiresApi; import androidx.core.content.ContextCompat; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ControlDispatcher; -import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.ForwardingPlayer; import com.google.android.exoplayer2.MediaMetadata; import com.google.android.exoplayer2.PlaybackException; @@ -57,12 +56,9 @@ import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline.Period; import com.google.android.exoplayer2.TracksInfo; 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.util.Assertions; 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.Util; import com.google.android.exoplayer2.video.VideoSize; @@ -1256,7 +1252,9 @@ public class PlayerView extends FrameLayout implements AdViewProvider { private void updateForCurrentTrackSelections(boolean isNewPlayer) { @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) { hideArtwork(); closeShutter(); @@ -1268,21 +1266,11 @@ public class PlayerView extends FrameLayout implements AdViewProvider { // Hide any video from the previous player. closeShutter(); } - - TrackSelectionArray trackSelections = player.getCurrentTrackSelections(); - for (int i = 0; i < trackSelections.length; i++) { - @Nullable TrackSelection trackSelection = trackSelections.get(i); - if (trackSelection != null) { - 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; - } - } - } + if (player.getCurrentTracksInfo().isTypeSelected(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. @@ -1518,7 +1506,7 @@ public class PlayerView extends FrameLayout implements AdViewProvider { Timeline timeline = player.getCurrentTimeline(); if (timeline.isEmpty()) { lastPeriodUidWithTracks = null; - } else if (!player.getCurrentTrackGroups().isEmpty()) { + } else if (!player.getCurrentTracksInfo().getTrackGroupInfos().isEmpty()) { lastPeriodUidWithTracks = timeline.getPeriod(player.getCurrentPeriodIndex(), period, /* setIds= */ true).uid; } else if (lastPeriodUidWithTracks != null) { diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/StyledPlayerControlView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/StyledPlayerControlView.java index 05360bc2a4..34e9786cfd 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/StyledPlayerControlView.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/StyledPlayerControlView.java @@ -32,6 +32,8 @@ import static com.google.android.exoplayer2.Player.EVENT_SEEK_FORWARD_INCREMENT_ import static com.google.android.exoplayer2.Player.EVENT_SHUFFLE_MODE_ENABLED_CHANGED; import static com.google.android.exoplayer2.Player.EVENT_TIMELINE_CHANGED; import static com.google.android.exoplayer2.Player.EVENT_TRACKS_CHANGED; +import static com.google.android.exoplayer2.trackselection.TrackSelectionUtil.clearTrackSelectionOverridesForType; +import static com.google.android.exoplayer2.trackselection.TrackSelectionUtil.forceTrackSelection; import static com.google.android.exoplayer2.util.Assertions.checkNotNull; import android.annotation.SuppressLint; @@ -59,7 +61,6 @@ import androidx.recyclerview.widget.RecyclerView; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ControlDispatcher; import com.google.android.exoplayer2.DefaultControlDispatcher; -import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.ExoPlayerLibraryInfo; import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.ForwardingPlayer; @@ -67,24 +68,23 @@ import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Player.Events; import com.google.android.exoplayer2.Player.State; import com.google.android.exoplayer2.Timeline; +import com.google.android.exoplayer2.TracksInfo; +import com.google.android.exoplayer2.TracksInfo.TrackGroupInfo; import com.google.android.exoplayer2.source.TrackGroup; -import com.google.android.exoplayer2.source.TrackGroupArray; -import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; -import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.ParametersBuilder; -import com.google.android.exoplayer2.trackselection.DefaultTrackSelector.SelectionOverride; -import com.google.android.exoplayer2.trackselection.MappingTrackSelector.MappedTrackInfo; -import com.google.android.exoplayer2.trackselection.TrackSelection; -import com.google.android.exoplayer2.trackselection.TrackSelectionArray; -import com.google.android.exoplayer2.trackselection.TrackSelector; +import com.google.android.exoplayer2.trackselection.TrackSelectionParameters; +import com.google.android.exoplayer2.trackselection.TrackSelectionParameters.TrackSelectionOverride; import com.google.android.exoplayer2.util.Assertions; import com.google.android.exoplayer2.util.RepeatModeUtil; import com.google.android.exoplayer2.util.Util; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableSet; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Formatter; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.concurrent.CopyOnWriteArrayList; /** @@ -437,9 +437,8 @@ public class StyledPlayerControlView extends FrameLayout { private boolean needToHideBars; private int settingsWindowMargin; - @Nullable private DefaultTrackSelector trackSelector; - private TrackSelectionAdapter textTrackSelectionAdapter; - private TrackSelectionAdapter audioTrackSelectionAdapter; + private TextTrackSelectionAdapter textTrackSelectionAdapter; + private AudioTrackSelectionAdapter audioTrackSelectionAdapter; // TODO(insun): Add setTrackNameProvider to use customized track name provider. private TrackNameProvider trackNameProvider; @@ -764,14 +763,6 @@ public class StyledPlayerControlView extends FrameLayout { if (player instanceof ForwardingPlayer) { player = ((ForwardingPlayer) player).getWrappedPlayer(); } - if (player instanceof ExoPlayer) { - TrackSelector trackSelector = ((ExoPlayer) player).getTrackSelector(); - if (trackSelector instanceof DefaultTrackSelector) { - this.trackSelector = (DefaultTrackSelector) trackSelector; - } - } else { - this.trackSelector = null; - } updateAll(); } @@ -818,7 +809,7 @@ public class StyledPlayerControlView extends FrameLayout { * @param listener The listener to be notified about visibility changes. */ public void addVisibilityListener(VisibilityListener listener) { - Assertions.checkNotNull(listener); + checkNotNull(listener); visibilityListeners.add(listener); } @@ -1254,58 +1245,46 @@ public class StyledPlayerControlView extends FrameLayout { private void initTrackSelectionAdapter() { textTrackSelectionAdapter.clear(); audioTrackSelectionAdapter.clear(); - if (player == null || trackSelector == null) { + if (player == null + || !player.isCommandAvailable(Player.COMMAND_GET_TRACK_INFOS) + || !player.isCommandAvailable(Player.COMMAND_SET_TRACK_SELECTION_PARAMETERS)) { return; } - DefaultTrackSelector trackSelector = this.trackSelector; - @Nullable MappedTrackInfo mappedTrackInfo = trackSelector.getCurrentMappedTrackInfo(); - if (mappedTrackInfo == null) { + TracksInfo tracksInfo = player.getCurrentTracksInfo(); + List trackGroupInfos = tracksInfo.getTrackGroupInfos(); + if (trackGroupInfos.isEmpty()) { return; } - List textTracks = new ArrayList<>(); - List audioTracks = new ArrayList<>(); - List textRendererIndices = new ArrayList<>(); - List audioRendererIndices = new ArrayList<>(); - for (int rendererIndex = 0; - rendererIndex < mappedTrackInfo.getRendererCount(); - rendererIndex++) { - if (mappedTrackInfo.getRendererType(rendererIndex) == C.TRACK_TYPE_TEXT + List textTracks = new ArrayList<>(); + List audioTracks = new ArrayList<>(); + for (int trackGroupIndex = 0; trackGroupIndex < trackGroupInfos.size(); trackGroupIndex++) { + TrackGroupInfo trackGroupInfo = trackGroupInfos.get(trackGroupIndex); + if (!trackGroupInfo.isSupported()) { + continue; + } + if (trackGroupInfo.getTrackType() == C.TRACK_TYPE_TEXT && controlViewLayoutManager.getShowButton(subtitleButton)) { // Get TrackSelection at the corresponding renderer index. - gatherTrackInfosForAdapter(mappedTrackInfo, rendererIndex, textTracks); - textRendererIndices.add(rendererIndex); - } else if (mappedTrackInfo.getRendererType(rendererIndex) == C.TRACK_TYPE_AUDIO) { - gatherTrackInfosForAdapter(mappedTrackInfo, rendererIndex, audioTracks); - audioRendererIndices.add(rendererIndex); + gatherTrackInfosForAdapter(tracksInfo, trackGroupIndex, textTracks); + } else if (trackGroupInfo.getTrackType() == C.TRACK_TYPE_AUDIO) { + gatherTrackInfosForAdapter(tracksInfo, trackGroupIndex, audioTracks); } } - textTrackSelectionAdapter.init(textRendererIndices, textTracks, mappedTrackInfo); - audioTrackSelectionAdapter.init(audioRendererIndices, audioTracks, mappedTrackInfo); + textTrackSelectionAdapter.init(textTracks); + audioTrackSelectionAdapter.init(audioTracks); } private void gatherTrackInfosForAdapter( - MappedTrackInfo mappedTrackInfo, int rendererIndex, List tracks) { - TrackGroupArray trackGroupArray = mappedTrackInfo.getTrackGroups(rendererIndex); + TracksInfo tracksInfo, int trackGroupIndex, List tracks) { - TrackSelectionArray trackSelections = checkNotNull(player).getCurrentTrackSelections(); - @Nullable TrackSelection trackSelection = trackSelections.get(rendererIndex); - - for (int groupIndex = 0; groupIndex < trackGroupArray.length; groupIndex++) { - TrackGroup trackGroup = trackGroupArray.get(groupIndex); - for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) { - Format format = trackGroup.getFormat(trackIndex); - if (mappedTrackInfo.getTrackSupport(rendererIndex, groupIndex, trackIndex) - == C.FORMAT_HANDLED) { - boolean trackIsSelected = - trackSelection != null && trackSelection.indexOf(format) != C.INDEX_UNSET; - tracks.add( - new TrackInfo( - rendererIndex, - groupIndex, - trackIndex, - trackNameProvider.getTrackName(format), - trackIsSelected)); - } + TrackGroupInfo trackGroupInfo = tracksInfo.getTrackGroupInfos().get(trackGroupIndex); + TrackGroup trackGroup = trackGroupInfo.getTrackGroup(); + for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) { + Format format = trackGroup.getFormat(trackIndex); + if (trackGroupInfo.isTrackSupported(trackIndex)) { + tracks.add( + new TrackInformation( + tracksInfo, trackGroupIndex, trackIndex, trackNameProvider.getTrackName(format))); } } } @@ -1988,33 +1967,36 @@ public class StyledPlayerControlView extends FrameLayout { } } - private static final class TrackInfo { + private static final class TrackInformation { - public final int rendererIndex; - public final int groupIndex; + private TracksInfo tracksInfo; + private int trackGroupIndex; + public final TrackGroupInfo trackGroupInfo; + public final TrackGroup trackGroup; public final int trackIndex; public final String trackName; - public final boolean selected; - public TrackInfo( - int rendererIndex, int groupIndex, int trackIndex, String trackName, boolean selected) { - this.rendererIndex = rendererIndex; - this.groupIndex = groupIndex; + public TrackInformation( + TracksInfo tracksInfo, int trackGroupIndex, int trackIndex, String trackName) { + this.tracksInfo = tracksInfo; + this.trackGroupIndex = trackGroupIndex; + this.trackGroupInfo = tracksInfo.getTrackGroupInfos().get(trackGroupIndex); + this.trackGroup = trackGroupInfo.getTrackGroup(); this.trackIndex = trackIndex; this.trackName = trackName; - this.selected = selected; + } + + public boolean isSelected() { + return trackGroupInfo.isTrackSelected(trackIndex); } } private final class TextTrackSelectionAdapter extends TrackSelectionAdapter { @Override - public void init( - List rendererIndices, - List trackInfos, - MappedTrackInfo mappedTrackInfo) { + public void init(List trackInformations) { boolean subtitleIsOn = false; - for (int i = 0; i < trackInfos.size(); i++) { - if (trackInfos.get(i).selected) { + for (int i = 0; i < trackInformations.size(); i++) { + if (trackInformations.get(i).isSelected()) { subtitleIsOn = true; break; } @@ -2026,9 +2008,7 @@ public class StyledPlayerControlView extends FrameLayout { subtitleButton.setContentDescription( subtitleIsOn ? subtitleOnContentDescription : subtitleOffContentDescription); } - this.rendererIndices = rendererIndices; - this.tracks = trackInfos; - this.mappedTrackInfo = mappedTrackInfo; + this.tracks = trackInformations; } @Override @@ -2037,7 +2017,7 @@ public class StyledPlayerControlView extends FrameLayout { holder.textView.setText(R.string.exo_track_selection_none); boolean isTrackSelectionOff = true; for (int i = 0; i < tracks.size(); i++) { - if (tracks.get(i).selected) { + if (tracks.get(i).isSelected()) { isTrackSelectionOff = false; break; } @@ -2045,16 +2025,18 @@ public class StyledPlayerControlView extends FrameLayout { holder.checkView.setVisibility(isTrackSelectionOff ? VISIBLE : INVISIBLE); holder.itemView.setOnClickListener( v -> { - if (trackSelector != null) { - ParametersBuilder parametersBuilder = trackSelector.getParameters().buildUpon(); - for (int i = 0; i < rendererIndices.size(); i++) { - int rendererIndex = rendererIndices.get(i); - parametersBuilder = - parametersBuilder - .clearSelectionOverrides(rendererIndex) - .setRendererDisabled(rendererIndex, true); - } - checkNotNull(trackSelector).setParameters(parametersBuilder); + if (player != null) { + TrackSelectionParameters trackSelectionParameters = + player.getTrackSelectionParameters(); + player.setTrackSelectionParameters( + trackSelectionParameters + .buildUpon() + .setDisabledTrackTypes( + new ImmutableSet.Builder<@C.TrackType Integer>() + .addAll(trackSelectionParameters.disabledTrackTypes) + .add(C.TRACK_TYPE_TEXT) + .build()) + .build()); settingsWindow.dismiss(); } }); @@ -2064,8 +2046,8 @@ public class StyledPlayerControlView extends FrameLayout { public void onBindViewHolder(SubSettingViewHolder holder, int position) { super.onBindViewHolder(holder, position); if (position > 0) { - TrackInfo track = tracks.get(position - 1); - holder.checkView.setVisibility(track.selected ? VISIBLE : INVISIBLE); + TrackInformation track = tracks.get(position - 1); + holder.checkView.setVisibility(track.isSelected() ? VISIBLE : INVISIBLE); } } @@ -2083,11 +2065,9 @@ public class StyledPlayerControlView extends FrameLayout { holder.textView.setText(R.string.exo_track_selection_auto); // hasSelectionOverride is true means there is an explicit track selection, not "Auto". boolean hasSelectionOverride = false; - DefaultTrackSelector.Parameters parameters = checkNotNull(trackSelector).getParameters(); - for (int i = 0; i < rendererIndices.size(); i++) { - int rendererIndex = rendererIndices.get(i); - TrackGroupArray trackGroups = checkNotNull(mappedTrackInfo).getTrackGroups(rendererIndex); - if (parameters.hasSelectionOverride(rendererIndex, trackGroups)) { + TrackSelectionParameters parameters = checkNotNull(player).getTrackSelectionParameters(); + for (int i = 0; i < tracks.size(); i++) { + if (parameters.trackSelectionOverrides.containsKey(tracks.get(i).trackGroup)) { hasSelectionOverride = true; break; } @@ -2095,14 +2075,20 @@ public class StyledPlayerControlView extends FrameLayout { holder.checkView.setVisibility(hasSelectionOverride ? INVISIBLE : VISIBLE); holder.itemView.setOnClickListener( v -> { - if (trackSelector != null) { - ParametersBuilder parametersBuilder = trackSelector.getParameters().buildUpon(); - for (int i = 0; i < rendererIndices.size(); i++) { - int rendererIndex = rendererIndices.get(i); - parametersBuilder = parametersBuilder.clearSelectionOverrides(rendererIndex); - } - checkNotNull(trackSelector).setParameters(parametersBuilder); + if (player == null) { + return; } + TrackSelectionParameters trackSelectionParameters = + player.getTrackSelectionParameters(); + // Remove all audio overrides. + ImmutableMap trackSelectionOverrides = + clearTrackSelectionOverridesForType( + C.TRACK_TYPE_AUDIO, trackSelectionParameters.trackSelectionOverrides); + player.setTrackSelectionParameters( + trackSelectionParameters + .buildUpon() + .setTrackSelectionOverrides(trackSelectionOverrides) + .build()); settingsAdapter.setSubTextAtPosition( SETTINGS_AUDIO_TRACK_SELECTION_POSITION, getResources().getString(R.string.exo_track_selection_auto)); @@ -2116,22 +2102,19 @@ public class StyledPlayerControlView extends FrameLayout { } @Override - public void init( - List rendererIndices, - List trackInfos, - MappedTrackInfo mappedTrackInfo) { + public void init(List trackInformations) { // Update subtext in settings menu with current audio track selection. boolean hasSelectionOverride = false; - for (int i = 0; i < rendererIndices.size(); i++) { - int rendererIndex = rendererIndices.get(i); - TrackGroupArray trackGroups = mappedTrackInfo.getTrackGroups(rendererIndex); - if (trackSelector != null - && trackSelector.getParameters().hasSelectionOverride(rendererIndex, trackGroups)) { + for (int i = 0; i < trackInformations.size(); i++) { + if (checkNotNull(player) + .getTrackSelectionParameters() + .trackSelectionOverrides + .containsKey(trackInformations.get(i).trackGroup)) { hasSelectionOverride = true; break; } } - if (trackInfos.isEmpty()) { + if (trackInformations.isEmpty()) { settingsAdapter.setSubTextAtPosition( SETTINGS_AUDIO_TRACK_SELECTION_POSITION, getResources().getString(R.string.exo_track_selection_none)); @@ -2142,35 +2125,28 @@ public class StyledPlayerControlView extends FrameLayout { SETTINGS_AUDIO_TRACK_SELECTION_POSITION, getResources().getString(R.string.exo_track_selection_auto)); } else { - for (int i = 0; i < trackInfos.size(); i++) { - TrackInfo track = trackInfos.get(i); - if (track.selected) { + for (int i = 0; i < trackInformations.size(); i++) { + TrackInformation track = trackInformations.get(i); + if (track.isSelected()) { settingsAdapter.setSubTextAtPosition( SETTINGS_AUDIO_TRACK_SELECTION_POSITION, track.trackName); break; } } } - this.rendererIndices = rendererIndices; - this.tracks = trackInfos; - this.mappedTrackInfo = mappedTrackInfo; + this.tracks = trackInformations; } } private abstract class TrackSelectionAdapter extends RecyclerView.Adapter { - protected List rendererIndices; - protected List tracks; - protected @Nullable MappedTrackInfo mappedTrackInfo; + protected List tracks; - public TrackSelectionAdapter() { - this.rendererIndices = new ArrayList<>(); + protected TrackSelectionAdapter() { this.tracks = new ArrayList<>(); - this.mappedTrackInfo = null; } - public abstract void init( - List rendererIndices, List trackInfos, MappedTrackInfo mappedTrackInfo); + public abstract void init(List trackInformations); @Override public SubSettingViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { @@ -2181,52 +2157,48 @@ public class StyledPlayerControlView extends FrameLayout { return new SubSettingViewHolder(v); } - public abstract void onBindViewHolderAtZeroPosition(SubSettingViewHolder holder); + protected abstract void onBindViewHolderAtZeroPosition(SubSettingViewHolder holder); - public abstract void onTrackSelection(String subtext); + protected abstract void onTrackSelection(String subtext); @Override public void onBindViewHolder(SubSettingViewHolder holder, int position) { - if (trackSelector == null || mappedTrackInfo == null) { + if (player == null) { return; } if (position == 0) { onBindViewHolderAtZeroPosition(holder); } else { - TrackInfo track = tracks.get(position - 1); - TrackGroupArray trackGroups = mappedTrackInfo.getTrackGroups(track.rendererIndex); + TrackInformation track = tracks.get(position - 1); boolean explicitlySelected = - checkNotNull(trackSelector) - .getParameters() - .hasSelectionOverride(track.rendererIndex, trackGroups) - && track.selected; + checkNotNull(player) + .getTrackSelectionParameters() + .trackSelectionOverrides + .containsKey(track.trackGroup) + && track.isSelected(); holder.textView.setText(track.trackName); holder.checkView.setVisibility(explicitlySelected ? VISIBLE : INVISIBLE); holder.itemView.setOnClickListener( v -> { - if (mappedTrackInfo != null && trackSelector != null) { - ParametersBuilder parametersBuilder = trackSelector.getParameters().buildUpon(); - for (int i = 0; i < rendererIndices.size(); i++) { - int rendererIndex = rendererIndices.get(i); - if (rendererIndex == track.rendererIndex) { - parametersBuilder = - parametersBuilder - .setSelectionOverride( - rendererIndex, - checkNotNull(mappedTrackInfo).getTrackGroups(rendererIndex), - new SelectionOverride(track.groupIndex, track.trackIndex)) - .setRendererDisabled(rendererIndex, false); - } else { - parametersBuilder = - parametersBuilder - .clearSelectionOverrides(rendererIndex) - .setRendererDisabled(rendererIndex, true); - } - } - checkNotNull(trackSelector).setParameters(parametersBuilder); - onTrackSelection(track.trackName); - settingsWindow.dismiss(); + if (player == null) { + return; } + TrackSelectionParameters trackSelectionParameters = + player.getTrackSelectionParameters(); + Map overrides = + forceTrackSelection( + trackSelectionParameters.trackSelectionOverrides, + track.tracksInfo, + track.trackGroupIndex, + new TrackSelectionOverride(ImmutableSet.of(track.trackIndex))); + checkNotNull(player) + .setTrackSelectionParameters( + trackSelectionParameters + .buildUpon() + .setTrackSelectionOverrides(overrides) + .build()); + onTrackSelection(track.trackName); + settingsWindow.dismiss(); }); } } @@ -2236,9 +2208,8 @@ public class StyledPlayerControlView extends FrameLayout { return tracks.isEmpty() ? 0 : tracks.size() + 1; } - public void clear() { + protected void clear() { tracks = Collections.emptyList(); - mappedTrackInfo = null; } } diff --git a/library/ui/src/main/java/com/google/android/exoplayer2/ui/StyledPlayerView.java b/library/ui/src/main/java/com/google/android/exoplayer2/ui/StyledPlayerView.java index 24bf154c77..e1263622d4 100644 --- a/library/ui/src/main/java/com/google/android/exoplayer2/ui/StyledPlayerView.java +++ b/library/ui/src/main/java/com/google/android/exoplayer2/ui/StyledPlayerView.java @@ -48,7 +48,6 @@ import androidx.annotation.RequiresApi; import androidx.core.content.ContextCompat; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ControlDispatcher; -import com.google.android.exoplayer2.Format; import com.google.android.exoplayer2.ForwardingPlayer; import com.google.android.exoplayer2.MediaMetadata; import com.google.android.exoplayer2.PlaybackException; @@ -58,12 +57,9 @@ import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline.Period; import com.google.android.exoplayer2.TracksInfo; 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.util.Assertions; 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.Util; import com.google.android.exoplayer2.video.VideoSize; @@ -1296,7 +1292,7 @@ public class StyledPlayerView extends FrameLayout implements AdViewProvider { private void updateForCurrentTrackSelections(boolean isNewPlayer) { @Nullable Player player = this.player; - if (player == null || player.getCurrentTrackGroups().isEmpty()) { + if (player == null || player.getCurrentTracksInfo().getTrackGroupInfos().isEmpty()) { if (!keepContentOnPlayerReset) { hideArtwork(); closeShutter(); @@ -1309,20 +1305,11 @@ public class StyledPlayerView extends FrameLayout implements AdViewProvider { closeShutter(); } - TrackSelectionArray trackSelections = player.getCurrentTrackSelections(); - for (int i = 0; i < trackSelections.length; i++) { - @Nullable TrackSelection trackSelection = trackSelections.get(i); - if (trackSelection != null) { - 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; - } - } - } + if (player.getCurrentTracksInfo().isTypeSelected(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. @@ -1558,7 +1545,7 @@ public class StyledPlayerView extends FrameLayout implements AdViewProvider { Timeline timeline = player.getCurrentTimeline(); if (timeline.isEmpty()) { lastPeriodUidWithTracks = null; - } else if (!player.getCurrentTrackGroups().isEmpty()) { + } else if (!player.getCurrentTracksInfo().getTrackGroupInfos().isEmpty()) { lastPeriodUidWithTracks = timeline.getPeriod(player.getCurrentPeriodIndex(), period, /* setIds= */ true).uid; } else if (lastPeriodUidWithTracks != null) {