Commit ac881be2 by krocard Committed by bachinger

Add TracksInfo to the Player API

TracksInfo is very similar to
`MappingTrackSelector.MappedTracksInfo` with some
fields removed to simplify the Player API,
notably it doesn't expose the renderer concept.

A significant difference is the addition of a `selected` boolean
field which avoids having a separate `getCurrentTrackSelection`
API.

This cl is a part of the bigger track selection change,
splitted for ease of review.

In particular, the MediaSession implementation and UI usage
have been slitted in child cls.

Find all cls with the tag:
#player-track-selection

PiperOrigin-RevId: 400937124
parent 47573d45
Showing with 427 additions and 59 deletions
......@@ -37,6 +37,7 @@ import com.google.android.exoplayer2.PlaybackException;
import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.TracksInfo;
import com.google.android.exoplayer2.audio.AudioAttributes;
import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.source.TrackGroupArray;
......@@ -66,6 +67,7 @@ import com.google.android.gms.common.api.PendingResult;
import com.google.android.gms.common.api.ResultCallback;
import com.google.common.collect.ImmutableList;
import java.util.List;
import org.checkerframework.checker.nullness.compatqual.NullableType;
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
/**
......@@ -101,7 +103,8 @@ public final class CastPlayer extends BasePlayer {
COMMAND_GET_TIMELINE,
COMMAND_GET_MEDIA_ITEMS_METADATA,
COMMAND_SET_MEDIA_ITEMS_METADATA,
COMMAND_CHANGE_MEDIA_ITEMS)
COMMAND_CHANGE_MEDIA_ITEMS,
COMMAND_GET_TRACK_INFOS)
.build();
public static final float MIN_SPEED_SUPPORTED = 0.5f;
......@@ -142,6 +145,7 @@ public final class CastPlayer extends BasePlayer {
private CastTimeline currentTimeline;
private TrackGroupArray currentTrackGroups;
private TrackSelectionArray currentTrackSelection;
private TracksInfo currentTracksInfo;
private Commands availableCommands;
@Player.State private int playbackState;
private int currentWindowIndex;
......@@ -219,6 +223,7 @@ public final class CastPlayer extends BasePlayer {
currentTimeline = CastTimeline.EMPTY_CAST_TIMELINE;
currentTrackGroups = TrackGroupArray.EMPTY;
currentTrackSelection = EMPTY_TRACK_SELECTION_ARRAY;
currentTracksInfo = TracksInfo.EMPTY;
availableCommands = new Commands.Builder().addAll(PERMANENT_AVAILABLE_COMMANDS).build();
pendingSeekWindowIndex = C.INDEX_UNSET;
pendingSeekPositionMs = C.TIME_UNSET;
......@@ -584,13 +589,18 @@ public final class CastPlayer extends BasePlayer {
}
@Override
public TrackGroupArray getCurrentTrackGroups() {
return currentTrackGroups;
}
@Override
public TrackSelectionArray getCurrentTrackSelections() {
return currentTrackSelection;
}
@Override
public TrackGroupArray getCurrentTrackGroups() {
return currentTrackGroups;
public TracksInfo getCurrentTracksInfo() {
return currentTracksInfo;
}
@Override
......@@ -871,6 +881,8 @@ public final class CastPlayer extends BasePlayer {
listeners.queueEvent(
Player.EVENT_TRACKS_CHANGED,
listener -> listener.onTracksChanged(currentTrackGroups, currentTrackSelection));
listeners.queueEvent(
Player.EVENT_TRACKS_CHANGED, listener -> listener.onTracksInfoChanged(currentTracksInfo));
}
updateAvailableCommandsAndNotifyIfChanged();
listeners.flushEvents();
......@@ -1032,6 +1044,7 @@ public final class CastPlayer extends BasePlayer {
boolean hasChanged = !currentTrackGroups.isEmpty();
currentTrackGroups = TrackGroupArray.EMPTY;
currentTrackSelection = EMPTY_TRACK_SELECTION_ARRAY;
currentTracksInfo = TracksInfo.EMPTY;
return hasChanged;
}
long[] activeTrackIds = mediaStatus.getActiveTrackIds();
......@@ -1040,7 +1053,9 @@ public final class CastPlayer extends BasePlayer {
}
TrackGroup[] trackGroups = new TrackGroup[castMediaTracks.size()];
TrackSelection[] trackSelections = new TrackSelection[RENDERER_COUNT];
@NullableType TrackSelection[] trackSelections = new TrackSelection[RENDERER_COUNT];
TracksInfo.TrackGroupInfo[] trackGroupInfos =
new TracksInfo.TrackGroupInfo[castMediaTracks.size()];
for (int i = 0; i < castMediaTracks.size(); i++) {
MediaTrack mediaTrack = castMediaTracks.get(i);
trackGroups[i] = new TrackGroup(CastUtils.mediaTrackToFormat(mediaTrack));
......@@ -1048,19 +1063,28 @@ public final class CastPlayer extends BasePlayer {
long id = mediaTrack.getId();
@C.TrackType int trackType = MimeTypes.getTrackType(mediaTrack.getContentType());
int rendererIndex = getRendererIndexForTrackType(trackType);
if (isTrackActive(id, activeTrackIds)
&& rendererIndex != C.INDEX_UNSET
&& trackSelections[rendererIndex] == null) {
boolean supported = rendererIndex != C.INDEX_UNSET;
boolean selected =
isTrackActive(id, activeTrackIds) && supported && trackSelections[rendererIndex] == null;
if (selected) {
trackSelections[rendererIndex] = new CastTrackSelection(trackGroups[i]);
}
@C.FormatSupport
int[] trackSupport = new int[] {supported ? C.FORMAT_HANDLED : C.FORMAT_UNSUPPORTED_TYPE};
final boolean[] trackSelected = new boolean[] {selected};
trackGroupInfos[i] =
new TracksInfo.TrackGroupInfo(trackGroups[i], trackSupport, trackType, trackSelected);
}
TrackGroupArray newTrackGroups = new TrackGroupArray(trackGroups);
TrackSelectionArray newTrackSelections = new TrackSelectionArray(trackSelections);
TracksInfo newTracksInfo = new TracksInfo(ImmutableList.copyOf(trackGroupInfos));
if (!newTrackGroups.equals(currentTrackGroups)
|| !newTrackSelections.equals(currentTrackSelection)) {
currentTrackSelection = new TrackSelectionArray(trackSelections);
currentTrackGroups = new TrackGroupArray(trackGroups);
|| !newTrackSelections.equals(currentTrackSelection)
|| !newTracksInfo.equals(currentTracksInfo)) {
currentTrackSelection = newTrackSelections;
currentTrackGroups = newTrackGroups;
currentTracksInfo = newTracksInfo;
return true;
}
return false;
......
......@@ -21,6 +21,7 @@ import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.TracksInfo;
import com.google.android.exoplayer2.testutil.StubExoPlayer;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import com.google.android.exoplayer2.trackselection.TrackSelectionParameters;
......@@ -241,6 +242,11 @@ import com.google.android.exoplayer2.util.ListenerSet;
}
@Override
public TracksInfo getCurrentTracksInfo() {
return TracksInfo.EMPTY;
}
@Override
public TrackSelectionParameters getTrackSelectionParameters() {
return TrackSelectionParameters.DEFAULT_WITHOUT_CONTEXT;
}
......
......@@ -361,6 +361,11 @@ public class ForwardingPlayer implements Player {
}
@Override
public TracksInfo getCurrentTracksInfo() {
return player.getCurrentTracksInfo();
}
@Override
public TrackSelectionParameters getTrackSelectionParameters() {
return player.getTrackSelectionParameters();
}
......@@ -646,6 +651,11 @@ public class ForwardingPlayer implements Player {
}
@Override
public void onTracksInfoChanged(TracksInfo tracksInfo) {
eventListener.onTracksInfoChanged(tracksInfo);
}
@Override
public void onMediaMetadataChanged(MediaMetadata mediaMetadata) {
eventListener.onMediaMetadataChanged(mediaMetadata);
}
......
......@@ -57,11 +57,8 @@ import java.util.List;
* <ul>
* <li>They can provide a {@link Timeline} representing the structure of the media being played,
* which can be obtained by calling {@link #getCurrentTimeline()}.
* <li>They can provide a {@link TrackGroupArray} defining the currently available tracks, which
* can be obtained by calling {@link #getCurrentTrackGroups()}.
* <li>They can provide a {@link TrackSelectionArray} defining which of the currently available
* tracks are selected to be rendered. This can be obtained by calling {@link
* #getCurrentTrackSelections()}}.
* <li>They can provide a {@link TracksInfo} defining the currently available tracks and which are
* selected to be rendered, which can be obtained by calling {@link #getCurrentTracksInfo()}.
* </ul>
*/
public interface Player {
......@@ -122,11 +119,23 @@ public interface Player {
* concrete implementation may include null elements if it has a fixed number of renderer
* components, wishes to report a TrackSelection for each of them, and has one or more
* renderer components that is not assigned any selected tracks.
* @deprecated Use {@link #onTracksInfoChanged(TracksInfo)} instead.
*/
@Deprecated
default void onTracksChanged(
TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {}
/**
* Called when the available or selected tracks change.
*
* <p>{@link #onEvents(Player, Events)} will also be called to report this event along with
* other events that happen in the same {@link Looper} message queue iteration.
*
* @param tracksInfo The available tracks information. Never null, but may be of length zero.
*/
default void onTracksInfoChanged(TracksInfo tracksInfo) {}
/**
* Called when the combined {@link MediaMetadata} changes.
*
* <p>The provided {@link MediaMetadata} is a combination of the {@link MediaItem#mediaMetadata}
......@@ -693,6 +702,7 @@ public interface Player {
COMMAND_SET_VIDEO_SURFACE,
COMMAND_GET_TEXT,
COMMAND_SET_TRACK_SELECTION_PARAMETERS,
COMMAND_GET_TRACK_INFOS,
};
private final FlagSet.Builder flagsBuilder;
......@@ -923,8 +933,7 @@ public interface Player {
@Nullable MediaItem mediaItem, @MediaItemTransitionReason int reason) {}
@Override
default void onTracksChanged(
TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {}
default void onTracksInfoChanged(TracksInfo tracksInfo) {}
@Override
default void onIsLoadingChanged(boolean isLoading) {}
......@@ -1278,7 +1287,7 @@ public interface Player {
int EVENT_TIMELINE_CHANGED = 0;
/** {@link #getCurrentMediaItem()} changed or the player started repeating the current item. */
int EVENT_MEDIA_ITEM_TRANSITION = 1;
/** {@link #getCurrentTrackGroups()} or {@link #getCurrentTrackSelections()} changed. */
/** {@link #getCurrentTracksInfo()} changed. */
int EVENT_TRACKS_CHANGED = 2;
/** {@link #isLoading()} ()} changed. */
int EVENT_IS_LOADING_CHANGED = 3;
......@@ -1331,8 +1340,8 @@ public interface Player {
* #COMMAND_CHANGE_MEDIA_ITEMS}, {@link #COMMAND_GET_AUDIO_ATTRIBUTES}, {@link
* #COMMAND_GET_VOLUME}, {@link #COMMAND_GET_DEVICE_VOLUME}, {@link #COMMAND_SET_VOLUME}, {@link
* #COMMAND_SET_DEVICE_VOLUME}, {@link #COMMAND_ADJUST_DEVICE_VOLUME}, {@link
* #COMMAND_SET_VIDEO_SURFACE}, {@link #COMMAND_GET_TEXT} or {@link
* #COMMAND_SET_TRACK_SELECTION_PARAMETERS}.
* #COMMAND_SET_VIDEO_SURFACE}, {@link #COMMAND_GET_TEXT}, {@link
* #COMMAND_SET_TRACK_SELECTION_PARAMETERS} or {@link #COMMAND_GET_TRACK_INFOS}.
*/
@Documented
@Retention(RetentionPolicy.SOURCE)
......@@ -1366,6 +1375,7 @@ public interface Player {
COMMAND_SET_VIDEO_SURFACE,
COMMAND_GET_TEXT,
COMMAND_SET_TRACK_SELECTION_PARAMETERS,
COMMAND_GET_TRACK_INFOS,
})
@interface Command {}
/** Command to start, pause or resume playback. */
......@@ -1424,6 +1434,8 @@ public interface Player {
int COMMAND_GET_TEXT = 27;
/** Command to set the player's track selection parameters. */
int COMMAND_SET_TRACK_SELECTION_PARAMETERS = 28;
/** Command to get track infos. */
int COMMAND_GET_TRACK_INFOS = 29;
/** Represents an invalid {@link Command}. */
int COMMAND_INVALID = -1;
......@@ -1962,7 +1974,9 @@ public interface Player {
* Returns the available track groups.
*
* @see Listener#onTracksChanged(TrackGroupArray, TrackSelectionArray)
* @deprecated Use {@link #getCurrentTracksInfo()}.
*/
@Deprecated
TrackGroupArray getCurrentTrackGroups();
/**
......@@ -1973,10 +1987,23 @@ public interface Player {
* components that is not assigned any selected tracks.
*
* @see Listener#onTracksChanged(TrackGroupArray, TrackSelectionArray)
* @deprecated Use {@link #getCurrentTracksInfo()}.
*/
@Deprecated
TrackSelectionArray getCurrentTrackSelections();
/** Returns the parameters constraining the track selection. */
/**
* Returns the available tracks, as well as the tracks' support, type, and selection status.
*
* @see Listener#onTracksChanged(TrackGroupArray, TrackSelectionArray)
*/
TracksInfo getCurrentTracksInfo();
/**
* Returns the parameters constraining the track selection.
*
* @see Listener#onTrackSelectionParametersChanged}
*/
TrackSelectionParameters getTrackSelectionParameters();
/**
......
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.exoplayer2;
import static com.google.common.truth.Truth.assertThat;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.google.android.exoplayer2.source.TrackGroup;
import com.google.common.collect.ImmutableList;
import org.junit.Test;
import org.junit.runner.RunWith;
/** Unit test for {@link TracksInfo}. */
@RunWith(AndroidJUnit4.class)
public class TracksInfoTest {
@Test
public void roundTripViaBundle_ofEmptyTracksInfo_yieldsEqualInstance() {
TracksInfo before = TracksInfo.EMPTY;
TracksInfo after = TracksInfo.CREATOR.fromBundle(before.toBundle());
assertThat(after).isEqualTo(before);
}
@Test
public void roundTripViaBundle_ofTracksInfo_yieldsEqualInstance() {
TracksInfo before =
new TracksInfo(
ImmutableList.of(
new TracksInfo.TrackGroupInfo(
new TrackGroup(new Format.Builder().build()),
new int[] {C.FORMAT_EXCEEDS_CAPABILITIES},
C.TRACK_TYPE_AUDIO,
new boolean[] {true}),
new TracksInfo.TrackGroupInfo(
new TrackGroup(new Format.Builder().build(), new Format.Builder().build()),
new int[] {C.FORMAT_UNSUPPORTED_DRM, C.FORMAT_UNSUPPORTED_TYPE},
C.TRACK_TYPE_VIDEO,
new boolean[] {false, true})));
TracksInfo after = TracksInfo.CREATOR.fromBundle(before.toBundle());
assertThat(after).isEqualTo(before);
}
@Test
public void tracksInfoGetters_withoutTrack_returnExpectedValues() {
TracksInfo tracksInfo = new TracksInfo(ImmutableList.of());
assertThat(tracksInfo.isTypeSupportedOrEmpty(C.TRACK_TYPE_AUDIO)).isTrue();
assertThat(tracksInfo.isTypeSelected(C.TRACK_TYPE_AUDIO)).isFalse();
ImmutableList<TracksInfo.TrackGroupInfo> trackGroupInfos = tracksInfo.getTrackGroupInfos();
assertThat(trackGroupInfos).isEmpty();
}
@Test
public void tracksInfo_emptyStaticInstance_isEmpty() {
TracksInfo tracksInfo = TracksInfo.EMPTY;
assertThat(tracksInfo.getTrackGroupInfos()).isEmpty();
assertThat(tracksInfo).isEqualTo(new TracksInfo(ImmutableList.of()));
}
@Test
public void tracksInfoGetters_ofComplexTracksInfo_returnExpectedValues() {
TracksInfo.TrackGroupInfo trackGroupInfo0 =
new TracksInfo.TrackGroupInfo(
new TrackGroup(new Format.Builder().build()),
new int[] {C.FORMAT_EXCEEDS_CAPABILITIES},
C.TRACK_TYPE_AUDIO,
/* tracksSelected= */ new boolean[] {false});
TracksInfo.TrackGroupInfo trackGroupInfo1 =
new TracksInfo.TrackGroupInfo(
new TrackGroup(new Format.Builder().build(), new Format.Builder().build()),
new int[] {C.FORMAT_UNSUPPORTED_DRM, C.FORMAT_HANDLED},
C.TRACK_TYPE_VIDEO,
/* tracksSelected= */ new boolean[] {false, true});
TracksInfo tracksInfo = new TracksInfo(ImmutableList.of(trackGroupInfo0, trackGroupInfo1));
assertThat(tracksInfo.isTypeSupportedOrEmpty(C.TRACK_TYPE_AUDIO)).isFalse();
assertThat(tracksInfo.isTypeSupportedOrEmpty(C.TRACK_TYPE_VIDEO)).isTrue();
assertThat(tracksInfo.isTypeSupportedOrEmpty(C.TRACK_TYPE_TEXT)).isTrue();
assertThat(tracksInfo.isTypeSelected(C.TRACK_TYPE_AUDIO)).isFalse();
assertThat(tracksInfo.isTypeSelected(C.TRACK_TYPE_VIDEO)).isTrue();
ImmutableList<TracksInfo.TrackGroupInfo> trackGroupInfos = tracksInfo.getTrackGroupInfos();
assertThat(trackGroupInfos).hasSize(2);
assertThat(trackGroupInfos.get(0)).isSameInstanceAs(trackGroupInfo0);
assertThat(trackGroupInfos.get(1)).isSameInstanceAs(trackGroupInfo1);
assertThat(trackGroupInfos.get(0).isTrackSupported(0)).isFalse();
assertThat(trackGroupInfos.get(1).isTrackSupported(0)).isFalse();
assertThat(trackGroupInfos.get(1).isTrackSupported(1)).isTrue();
assertThat(trackGroupInfos.get(0).getTrackSupport(0)).isEqualTo(C.FORMAT_EXCEEDS_CAPABILITIES);
assertThat(trackGroupInfos.get(1).getTrackSupport(0)).isEqualTo(C.FORMAT_UNSUPPORTED_DRM);
assertThat(trackGroupInfos.get(1).getTrackSupport(1)).isEqualTo(C.FORMAT_HANDLED);
assertThat(trackGroupInfos.get(0).isTrackSelected(0)).isFalse();
assertThat(trackGroupInfos.get(1).isTrackSelected(0)).isFalse();
assertThat(trackGroupInfos.get(1).isTrackSelected(1)).isTrue();
assertThat(trackGroupInfos.get(0).getTrackType()).isEqualTo(C.TRACK_TYPE_AUDIO);
assertThat(trackGroupInfos.get(1).getTrackType()).isEqualTo(C.TRACK_TYPE_VIDEO);
}
}
......@@ -196,6 +196,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
new TrackSelectorResult(
new RendererConfiguration[renderers.length],
new ExoTrackSelection[renderers.length],
TracksInfo.EMPTY,
/* info= */ null);
period = new Timeline.Period();
permanentAvailableCommands =
......@@ -210,7 +211,8 @@ import java.util.concurrent.CopyOnWriteArraySet;
COMMAND_GET_TIMELINE,
COMMAND_GET_MEDIA_ITEMS_METADATA,
COMMAND_SET_MEDIA_ITEMS_METADATA,
COMMAND_CHANGE_MEDIA_ITEMS)
COMMAND_CHANGE_MEDIA_ITEMS,
COMMAND_GET_TRACK_INFOS)
.addIf(COMMAND_SET_TRACK_SELECTION_PARAMETERS, trackSelector.isSetParametersSupported())
.addAll(additionalPermanentAvailableCommands)
.build();
......@@ -952,6 +954,11 @@ import java.util.concurrent.CopyOnWriteArraySet;
}
@Override
public TracksInfo getCurrentTracksInfo() {
return playbackInfo.trackSelectorResult.tracksInfo;
}
@Override
public TrackSelectionParameters getTrackSelectionParameters() {
return trackSelector.getParameters();
}
......@@ -1274,6 +1281,9 @@ import java.util.concurrent.CopyOnWriteArraySet;
listeners.queueEvent(
Player.EVENT_TRACKS_CHANGED,
listener -> listener.onTracksChanged(newPlaybackInfo.trackGroups, newSelection));
listeners.queueEvent(
Player.EVENT_TRACKS_CHANGED,
listener -> listener.onTracksInfoChanged(newPlaybackInfo.trackSelectorResult.tracksInfo));
}
if (metadataChanged) {
final MediaMetadata finalMediaMetadata = mediaMetadata;
......
......@@ -1457,6 +1457,12 @@ public class SimpleExoPlayer extends BasePlayer
}
@Override
public TracksInfo getCurrentTracksInfo() {
verifyApplicationThread();
return player.getCurrentTracksInfo();
}
@Override
public TrackSelectionParameters getTrackSelectionParameters() {
verifyApplicationThread();
return player.getTrackSelectionParameters();
......
......@@ -35,6 +35,7 @@ import com.google.android.exoplayer2.Player.PlaybackSuppressionReason;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.Timeline.Period;
import com.google.android.exoplayer2.Timeline.Window;
import com.google.android.exoplayer2.TracksInfo;
import com.google.android.exoplayer2.analytics.AnalyticsListener.EventTime;
import com.google.android.exoplayer2.audio.AudioAttributes;
import com.google.android.exoplayer2.audio.AudioRendererEventListener;
......@@ -586,6 +587,7 @@ public class AnalyticsCollector
}
@Override
@SuppressWarnings("deprecation") // Implementing and calling deprecate listener method
public final void onTracksChanged(
TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
EventTime eventTime = generateCurrentPlayerMediaPeriodEventTime();
......@@ -595,6 +597,15 @@ public class AnalyticsCollector
listener -> listener.onTracksChanged(eventTime, trackGroups, trackSelections));
}
@Override
public void onTracksInfoChanged(TracksInfo tracksInfo) {
EventTime eventTime = generateCurrentPlayerMediaPeriodEventTime();
sendEvent(
eventTime,
AnalyticsListener.EVENT_TRACKS_CHANGED,
listener -> listener.onTracksInfoChanged(eventTime, tracksInfo));
}
@SuppressWarnings("deprecation") // Calling deprecated listener method.
@Override
public final void onIsLoadingChanged(boolean isLoading) {
......
......@@ -36,6 +36,7 @@ import com.google.android.exoplayer2.Player.DiscontinuityReason;
import com.google.android.exoplayer2.Player.PlaybackSuppressionReason;
import com.google.android.exoplayer2.Player.TimelineChangeReason;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.TracksInfo;
import com.google.android.exoplayer2.audio.AudioAttributes;
import com.google.android.exoplayer2.audio.AudioSink;
import com.google.android.exoplayer2.decoder.DecoderCounters;
......@@ -221,7 +222,8 @@ public interface AnalyticsListener {
*/
int EVENT_MEDIA_ITEM_TRANSITION = Player.EVENT_MEDIA_ITEM_TRANSITION;
/**
* {@link Player#getCurrentTrackGroups()} or {@link Player#getCurrentTrackSelections()} changed.
* {@link Player#getCurrentTracksInfo()}, {@link Player#getCurrentTrackGroups()} or {@link
* Player#getCurrentTrackSelections()} changed.
*/
int EVENT_TRACKS_CHANGED = Player.EVENT_TRACKS_CHANGED;
/** {@link Player#isLoading()} ()} changed. */
......@@ -674,11 +676,21 @@ public interface AnalyticsListener {
* @param eventTime The event time.
* @param trackGroups The available tracks. May be empty.
* @param trackSelections The track selections for each renderer. May contain null elements.
* @deprecated Use {@link #onTracksInfoChanged}.
*/
@Deprecated
default void onTracksChanged(
EventTime eventTime, TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {}
/**
* Called when the available or selected tracks change.
*
* @param eventTime The event time.
* @param tracksInfo The available tracks information. Never null, but may be of length zero.
*/
default void onTracksInfoChanged(EventTime eventTime, TracksInfo tracksInfo) {}
/**
* Called when the combined {@link MediaMetadata} changes.
*
* <p>The provided {@link MediaMetadata} is a combination of the {@link MediaItem#mediaMetadata}
......
......@@ -21,6 +21,7 @@ import static java.lang.Math.min;
import android.util.Pair;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.C.FormatSupport;
import com.google.android.exoplayer2.ExoPlaybackException;
......@@ -30,11 +31,13 @@ import com.google.android.exoplayer2.RendererCapabilities.AdaptiveSupport;
import com.google.android.exoplayer2.RendererCapabilities.Capabilities;
import com.google.android.exoplayer2.RendererConfiguration;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.TracksInfo;
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.Util;
import com.google.common.collect.ImmutableList;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
......@@ -106,7 +109,7 @@ public abstract class MappingTrackSelector extends TrackSelector {
* renderer, track group and track (in that order).
* @param unmappedTrackGroups {@link TrackGroup}s not mapped to any renderer.
*/
@SuppressWarnings("deprecation")
@VisibleForTesting
/* package */ MappedTrackInfo(
String[] rendererNames,
@C.TrackType int[] rendererTrackTypes,
......@@ -144,7 +147,7 @@ public abstract class MappingTrackSelector extends TrackSelector {
*
* @see Renderer#getTrackType()
* @param rendererIndex The renderer index.
* @return One of the {@code TRACK_TYPE_*} constants defined in {@link C}.
* @return The {@link C.TrackType} of the renderer.
*/
public @C.TrackType int getRendererType(int rendererIndex) {
return rendererTrackTypes[rendererIndex];
......@@ -279,6 +282,7 @@ public abstract class MappingTrackSelector extends TrackSelector {
String firstSampleMimeType = null;
for (int i = 0; i < trackIndices.length; i++) {
int trackIndex = trackIndices[i];
@Nullable
String sampleMimeType =
rendererTrackGroups[rendererIndex].get(groupIndex).getFormat(trackIndex).sampleMimeType;
if (handledTrackCount++ == 0) {
......@@ -406,7 +410,10 @@ public abstract class MappingTrackSelector extends TrackSelector {
rendererMixedMimeTypeAdaptationSupports,
periodId,
timeline);
return new TrackSelectorResult(result.first, result.second, mappedTrackInfo);
TracksInfo tracksInfo = buildTracksInfo(result.second, mappedTrackInfo);
return new TrackSelectorResult(result.first, result.second, tracksInfo, mappedTrackInfo);
}
/**
......@@ -536,4 +543,49 @@ public abstract class MappingTrackSelector extends TrackSelector {
}
return mixedMimeTypeAdaptationSupport;
}
@VisibleForTesting
/* package */ static TracksInfo buildTracksInfo(
@NullableType TrackSelection[] selections, MappedTrackInfo mappedTrackInfo) {
ImmutableList.Builder<TracksInfo.TrackGroupInfo> builder = new ImmutableList.Builder<>();
for (int rendererIndex = 0;
rendererIndex < mappedTrackInfo.getRendererCount();
rendererIndex++) {
TrackGroupArray trackGroupArray = mappedTrackInfo.getTrackGroups(rendererIndex);
@Nullable TrackSelection trackSelection = selections[rendererIndex];
for (int groupIndex = 0; groupIndex < trackGroupArray.length; groupIndex++) {
TrackGroup trackGroup = trackGroupArray.get(groupIndex);
@C.FormatSupport int[] trackSupport = new int[trackGroup.length];
boolean[] selected = new boolean[trackGroup.length];
for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) {
trackSupport[trackIndex] =
mappedTrackInfo.getTrackSupport(rendererIndex, groupIndex, trackIndex);
// Suppressing reference equality warning because the track group stored in the track
// selection must point to the exact track group object to be considered part of it.
@SuppressWarnings("ReferenceEquality")
boolean isTrackSelected =
(trackSelection != null)
&& (trackSelection.getTrackGroup() == trackGroup)
&& (trackSelection.indexOf(trackIndex) != C.INDEX_UNSET);
selected[trackIndex] = isTrackSelected;
}
@C.TrackType int trackGroupType = mappedTrackInfo.getRendererType(rendererIndex);
builder.add(
new TracksInfo.TrackGroupInfo(trackGroup, trackSupport, trackGroupType, selected));
}
}
TrackGroupArray unmappedTrackGroups = mappedTrackInfo.getUnmappedTrackGroups();
for (int groupIndex = 0; groupIndex < unmappedTrackGroups.length; groupIndex++) {
TrackGroup trackGroup = unmappedTrackGroups.get(groupIndex);
@C.FormatSupport int[] trackSupport = new int[trackGroup.length];
Arrays.fill(trackSupport, C.FORMAT_UNSUPPORTED_TYPE);
// A track group only contains tracks of the same type, thus only consider the first track.
@C.TrackType
int trackGroupType = MimeTypes.getTrackType(trackGroup.getFormat(0).sampleMimeType);
boolean[] selected = new boolean[trackGroup.length]; // Initialized to false.
builder.add(
new TracksInfo.TrackGroupInfo(trackGroup, trackSupport, trackGroupType, selected));
}
return new TracksInfo(builder.build());
}
}
......@@ -17,6 +17,7 @@ package com.google.android.exoplayer2.trackselection;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.RendererConfiguration;
import com.google.android.exoplayer2.TracksInfo;
import com.google.android.exoplayer2.util.Util;
import org.checkerframework.checker.nullness.compatqual.NullableType;
......@@ -32,6 +33,8 @@ public final class TrackSelectorResult {
public final @NullableType RendererConfiguration[] rendererConfigurations;
/** A {@link ExoTrackSelection} array containing the track selection for each renderer. */
public final @NullableType ExoTrackSelection[] selections;
/** Describe the tracks and which one were selected. */
public final TracksInfo tracksInfo;
/**
* An opaque object that will be returned to {@link TrackSelector#onSelectionActivated(Object)}
* should the selections be activated.
......@@ -45,13 +48,34 @@ public final class TrackSelectorResult {
* @param info An opaque object that will be returned to {@link
* TrackSelector#onSelectionActivated(Object)} should the selection be activated. May be
* {@code null}.
* @deprecated Use {@link #TrackSelectorResult(RendererConfiguration[], ExoTrackSelection[],
* TracksInfo, Object)}.
*/
@Deprecated
public TrackSelectorResult(
@NullableType RendererConfiguration[] rendererConfigurations,
@NullableType ExoTrackSelection[] selections,
@Nullable Object info) {
this(rendererConfigurations, selections, TracksInfo.EMPTY, info);
}
/**
* @param rendererConfigurations A {@link RendererConfiguration} for each renderer. A null entry
* indicates the corresponding renderer should be disabled.
* @param selections A {@link ExoTrackSelection} array containing the selection for each renderer.
* @param tracksInfo Description of the available tracks and which one were selected.
* @param info An opaque object that will be returned to {@link
* TrackSelector#onSelectionActivated(Object)} should the selection be activated. May be
* {@code null}.
*/
public TrackSelectorResult(
@NullableType RendererConfiguration[] rendererConfigurations,
@NullableType ExoTrackSelection[] selections,
TracksInfo tracksInfo,
@Nullable Object info) {
this.rendererConfigurations = rendererConfigurations;
this.selections = selections.clone();
this.tracksInfo = tracksInfo;
this.info = info;
length = rendererConfigurations.length;
}
......
......@@ -23,6 +23,7 @@ import static com.google.android.exoplayer2.Player.COMMAND_GET_DEVICE_VOLUME;
import static com.google.android.exoplayer2.Player.COMMAND_GET_MEDIA_ITEMS_METADATA;
import static com.google.android.exoplayer2.Player.COMMAND_GET_TEXT;
import static com.google.android.exoplayer2.Player.COMMAND_GET_TIMELINE;
import static com.google.android.exoplayer2.Player.COMMAND_GET_TRACK_INFOS;
import static com.google.android.exoplayer2.Player.COMMAND_GET_VOLUME;
import static com.google.android.exoplayer2.Player.COMMAND_PLAY_PAUSE;
import static com.google.android.exoplayer2.Player.COMMAND_PREPARE_STOP;
......@@ -8344,6 +8345,7 @@ public final class ExoPlayerTest {
assertThat(player.isCommandAvailable(COMMAND_SET_VIDEO_SURFACE)).isTrue();
assertThat(player.isCommandAvailable(COMMAND_GET_TEXT)).isTrue();
assertThat(player.isCommandAvailable(COMMAND_SET_TRACK_SELECTION_PARAMETERS)).isTrue();
assertThat(player.isCommandAvailable(COMMAND_GET_TRACK_INFOS)).isTrue();
}
@Test
......@@ -11238,7 +11240,8 @@ public final class ExoPlayerTest {
COMMAND_ADJUST_DEVICE_VOLUME,
COMMAND_SET_VIDEO_SURFACE,
COMMAND_GET_TEXT,
COMMAND_SET_TRACK_SELECTION_PARAMETERS);
COMMAND_SET_TRACK_SELECTION_PARAMETERS,
COMMAND_GET_TRACK_INFOS);
if (!isTimelineEmpty) {
builder.add(COMMAND_SEEK_TO_PREVIOUS);
}
......
......@@ -771,7 +771,10 @@ public final class MediaPeriodQueueTest {
mediaSourceList,
getNextMediaPeriodInfo(),
new TrackSelectorResult(
new RendererConfiguration[0], new ExoTrackSelection[0], /* info= */ null));
new RendererConfiguration[0],
new ExoTrackSelection[0],
TracksInfo.EMPTY,
/* info= */ null));
}
private void clear() {
......
......@@ -84,6 +84,7 @@ import com.google.android.exoplayer2.RenderersFactory;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.Timeline.Window;
import com.google.android.exoplayer2.TracksInfo;
import com.google.android.exoplayer2.decoder.DecoderCounters;
import com.google.android.exoplayer2.drm.DefaultDrmSessionManager;
import com.google.android.exoplayer2.drm.DrmInitData;
......@@ -100,7 +101,6 @@ import com.google.android.exoplayer2.source.LoadEventInfo;
import com.google.android.exoplayer2.source.MediaLoadData;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.source.ads.AdPlaybackState;
import com.google.android.exoplayer2.testutil.ActionSchedule;
import com.google.android.exoplayer2.testutil.ActionSchedule.PlayerRunnable;
......@@ -115,7 +115,6 @@ import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinit
import com.google.android.exoplayer2.testutil.FakeVideoRenderer;
import com.google.android.exoplayer2.testutil.TestExoPlayerBuilder;
import com.google.android.exoplayer2.testutil.TestUtil;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import com.google.android.exoplayer2.util.Clock;
import com.google.android.exoplayer2.util.ConditionVariable;
import com.google.android.exoplayer2.util.MimeTypes;
......@@ -2224,8 +2223,7 @@ public final class AnalyticsCollectorTest {
}
@Override
public void onTracksChanged(
EventTime eventTime, TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
public void onTracksInfoChanged(EventTime eventTime, TracksInfo tracksInfo) {
reportedEvents.add(new ReportedEvent(EVENT_TRACKS_CHANGED, eventTime));
}
......
......@@ -38,6 +38,7 @@ import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.RendererCapabilities;
import com.google.android.exoplayer2.RendererConfiguration;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.TracksInfo;
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.source.TrackGroupArray;
......@@ -50,6 +51,7 @@ import com.google.android.exoplayer2.trackselection.TrackSelector.InvalidationLi
import com.google.android.exoplayer2.upstream.BandwidthMeter;
import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.Util;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import java.util.HashMap;
......@@ -1717,6 +1719,32 @@ public final class DefaultTrackSelectorTest {
assertFixedSelection(result.selections[0], trackGroups, formatAac);
}
/** Tests audio track selection when there are multiple audio renderers. */
@Test
public void selectTracks_multipleRenderer_allSelected() throws Exception {
RendererCapabilities[] rendererCapabilities =
new RendererCapabilities[] {VIDEO_CAPABILITIES, AUDIO_CAPABILITIES, AUDIO_CAPABILITIES};
TrackGroupArray trackGroups = new TrackGroupArray(AUDIO_TRACK_GROUP);
TrackSelectorResult result =
trackSelector.selectTracks(rendererCapabilities, trackGroups, periodId, TIMELINE);
assertThat(result.length).isEqualTo(3);
assertThat(result.rendererConfigurations)
.asList()
.containsExactly(null, DEFAULT, null)
.inOrder();
assertThat(result.selections[0]).isNull();
assertFixedSelection(result.selections[1], trackGroups, trackGroups.get(0).getFormat(0));
assertThat(result.selections[2]).isNull();
ImmutableList<TracksInfo.TrackGroupInfo> trackGroupInfos =
result.tracksInfo.getTrackGroupInfos();
assertThat(trackGroupInfos).hasSize(1);
assertThat(trackGroupInfos.get(0).getTrackGroup()).isEqualTo(AUDIO_TRACK_GROUP);
assertThat(trackGroupInfos.get(0).isTrackSelected(0)).isTrue();
assertThat(trackGroupInfos.get(0).getTrackSupport(0)).isEqualTo(FORMAT_HANDLED);
}
private static void assertSelections(TrackSelectorResult result, TrackSelection[] expected) {
assertThat(result.length).isEqualTo(expected.length);
for (int i = 0; i < expected.length; i++) {
......
......@@ -27,12 +27,15 @@ import com.google.android.exoplayer2.RendererCapabilities.AdaptiveSupport;
import com.google.android.exoplayer2.RendererCapabilities.Capabilities;
import com.google.android.exoplayer2.RendererConfiguration;
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.MediaSource.MediaPeriodId;
import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.testutil.FakeTimeline;
import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.Util;
import com.google.common.collect.ImmutableList;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
......@@ -129,6 +132,61 @@ public final class MappingTrackSelectorTest {
return new TrackGroup(new Format.Builder().setSampleMimeType(sampleMimeType).build());
}
@Test
public void buildTrackInfos_withTestValues_isAsExpected() {
MappingTrackSelector.MappedTrackInfo mappedTrackInfo =
new MappingTrackSelector.MappedTrackInfo(
new String[] {"1", "2"},
new int[] {C.TRACK_TYPE_AUDIO, C.TRACK_TYPE_VIDEO},
new TrackGroupArray[] {
new TrackGroupArray(
new TrackGroup(new Format.Builder().build()),
new TrackGroup(new Format.Builder().build())),
new TrackGroupArray(
new TrackGroup(new Format.Builder().build(), new Format.Builder().build()))
},
new int[] {
RendererCapabilities.ADAPTIVE_SEAMLESS, RendererCapabilities.ADAPTIVE_NOT_SUPPORTED
},
new int[][][] {
new int[][] {new int[] {C.FORMAT_HANDLED}, new int[] {C.FORMAT_UNSUPPORTED_SUBTYPE}},
new int[][] {new int[] {C.FORMAT_UNSUPPORTED_DRM, C.FORMAT_EXCEEDS_CAPABILITIES}}
},
new TrackGroupArray(new TrackGroup(new Format.Builder().build())));
TrackSelection[] selections =
new TrackSelection[] {
new FixedTrackSelection(mappedTrackInfo.getTrackGroups(0).get(1), 0),
new FixedTrackSelection(mappedTrackInfo.getTrackGroups(1).get(0), 1)
};
TracksInfo tracksInfo = MappingTrackSelector.buildTracksInfo(selections, mappedTrackInfo);
ImmutableList<TrackGroupInfo> trackGroupInfos = tracksInfo.getTrackGroupInfos();
assertThat(trackGroupInfos).hasSize(4);
assertThat(trackGroupInfos.get(0).getTrackGroup())
.isEqualTo(mappedTrackInfo.getTrackGroups(0).get(0));
assertThat(trackGroupInfos.get(1).getTrackGroup())
.isEqualTo(mappedTrackInfo.getTrackGroups(0).get(1));
assertThat(trackGroupInfos.get(2).getTrackGroup())
.isEqualTo(mappedTrackInfo.getTrackGroups(1).get(0));
assertThat(trackGroupInfos.get(3).getTrackGroup())
.isEqualTo(mappedTrackInfo.getUnmappedTrackGroups().get(0));
assertThat(trackGroupInfos.get(0).getTrackSupport(0)).isEqualTo(C.FORMAT_HANDLED);
assertThat(trackGroupInfos.get(1).getTrackSupport(0)).isEqualTo(C.FORMAT_UNSUPPORTED_SUBTYPE);
assertThat(trackGroupInfos.get(2).getTrackSupport(0)).isEqualTo(C.FORMAT_UNSUPPORTED_DRM);
assertThat(trackGroupInfos.get(2).getTrackSupport(1)).isEqualTo(C.FORMAT_EXCEEDS_CAPABILITIES);
assertThat(trackGroupInfos.get(3).getTrackSupport(0)).isEqualTo(C.FORMAT_UNSUPPORTED_TYPE);
assertThat(trackGroupInfos.get(0).isTrackSelected(0)).isFalse();
assertThat(trackGroupInfos.get(1).isTrackSelected(0)).isTrue();
assertThat(trackGroupInfos.get(2).isTrackSelected(0)).isFalse();
assertThat(trackGroupInfos.get(2).isTrackSelected(1)).isTrue();
assertThat(trackGroupInfos.get(3).isTrackSelected(0)).isFalse();
assertThat(trackGroupInfos.get(0).getTrackType()).isEqualTo(C.TRACK_TYPE_AUDIO);
assertThat(trackGroupInfos.get(1).getTrackType()).isEqualTo(C.TRACK_TYPE_AUDIO);
assertThat(trackGroupInfos.get(2).getTrackType()).isEqualTo(C.TRACK_TYPE_VIDEO);
assertThat(trackGroupInfos.get(3).getTrackType()).isEqualTo(C.TRACK_TYPE_UNKNOWN);
}
/**
* A {@link MappingTrackSelector} that stashes the {@link MappedTrackInfo} passed to {@link
* #selectTracks(MappedTrackInfo, int[][][], int[], MediaPeriodId, Timeline)}.
......
......@@ -45,6 +45,7 @@ import com.google.android.exoplayer2.Renderer;
import com.google.android.exoplayer2.RenderersFactory;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.TracksInfo;
import com.google.android.exoplayer2.analytics.AnalyticsListener;
import com.google.android.exoplayer2.audio.AudioRendererEventListener;
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
......@@ -53,10 +54,8 @@ import com.google.android.exoplayer2.metadata.MetadataOutput;
import com.google.android.exoplayer2.source.DefaultMediaSourceFactory;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.MediaSourceFactory;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.text.TextOutput;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import com.google.android.exoplayer2.util.Clock;
import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.Util;
......@@ -636,8 +635,7 @@ public final class Transformer {
}
@Override
public void onTracksChanged(
EventTime eventTime, TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
public void onTracksInfoChanged(EventTime eventTime, TracksInfo tracksInfo) {
if (muxerWrapper.getTrackCount() == 0) {
handleTransformationEnded(
new IllegalStateException(
......
......@@ -56,7 +56,7 @@ import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Player.DiscontinuityReason;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.Timeline.Period;
import com.google.android.exoplayer2.source.TrackGroupArray;
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;
......@@ -1511,7 +1511,7 @@ public class PlayerView extends FrameLayout implements AdViewProvider {
}
@Override
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray selections) {
public void onTracksInfoChanged(TracksInfo tracksInfo) {
// Suppress the update if transitioning to an unprepared period within the same window. This
// is necessary to avoid closing the shutter when such a transition occurs. See:
// https://github.com/google/ExoPlayer/issues/5507.
......
......@@ -57,7 +57,7 @@ import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Player.DiscontinuityReason;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.Timeline.Period;
import com.google.android.exoplayer2.source.TrackGroupArray;
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;
......@@ -1551,7 +1551,7 @@ public class StyledPlayerView extends FrameLayout implements AdViewProvider {
}
@Override
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray selections) {
public void onTracksInfoChanged(TracksInfo tracksInfo) {
// Suppress the update if transitioning to an unprepared period within the same window. This
// is necessary to avoid closing the shutter when such a transition occurs. See:
// https://github.com/google/ExoPlayer/issues/5507.
......
......@@ -38,9 +38,7 @@ import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.analytics.AnalyticsListener;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
import com.google.android.exoplayer2.upstream.BandwidthMeter;
import com.google.android.exoplayer2.util.Clock;
import com.google.android.exoplayer2.util.HandlerWrapper;
......@@ -383,7 +381,6 @@ public final class ExoPlayerTestRunner implements Player.Listener, ActionSchedul
private SimpleExoPlayer player;
private Exception exception;
private TrackGroupArray trackGroups;
private boolean playerWasPrepared;
private ExoPlayerTestRunner(
......@@ -563,17 +560,6 @@ public final class ExoPlayerTestRunner implements Player.Listener, ActionSchedul
}
/**
* Asserts that the last track group array reported by {@link
* Player.Listener#onTracksChanged(TrackGroupArray, TrackSelectionArray)} is equal to the provided
* track group array.
*
* @param trackGroupArray The expected {@link TrackGroupArray}.
*/
public void assertTrackGroupsEqual(TrackGroupArray trackGroupArray) {
assertThat(this.trackGroups).isEqualTo(trackGroupArray);
}
/**
* Asserts that {@link Player.Listener#onPositionDiscontinuity(Player.PositionInfo,
* Player.PositionInfo, int)} was not called.
*/
......@@ -657,11 +643,6 @@ public final class ExoPlayerTestRunner implements Player.Listener, ActionSchedul
}
@Override
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
this.trackGroups = trackGroups;
}
@Override
public void onPlaybackStateChanged(@Player.State int playbackState) {
playbackStates.add(playbackState);
playerWasPrepared |= playbackState != Player.STATE_IDLE;
......
......@@ -33,6 +33,7 @@ import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.PlayerMessage;
import com.google.android.exoplayer2.SeekParameters;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.TracksInfo;
import com.google.android.exoplayer2.audio.AudioAttributes;
import com.google.android.exoplayer2.audio.AuxEffectInfo;
import com.google.android.exoplayer2.source.MediaSource;
......@@ -464,6 +465,11 @@ public class StubExoPlayer extends BasePlayer implements ExoPlayer {
}
@Override
public TracksInfo getCurrentTracksInfo() {
throw new UnsupportedOperationException();
}
@Override
public TrackSelectionParameters getTrackSelectionParameters() {
throw new UnsupportedOperationException();
}
......
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