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
This commit is contained in:
parent
47573d4575
commit
ac881be2fc
@ -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;
|
||||
@ -583,14 +588,19 @@ public final class CastPlayer extends BasePlayer {
|
||||
return false;
|
||||
}
|
||||
|
||||
@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;
|
||||
@ -240,6 +241,11 @@ import com.google.android.exoplayer2.util.ListenerSet;
|
||||
return new TrackSelectionArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TracksInfo getCurrentTracksInfo() {
|
||||
return TracksInfo.EMPTY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackSelectionParameters getTrackSelectionParameters() {
|
||||
return TrackSelectionParameters.DEFAULT_WITHOUT_CONTEXT;
|
||||
|
@ -360,6 +360,11 @@ public class ForwardingPlayer implements Player {
|
||||
return player.getCurrentTrackSelections();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TracksInfo getCurrentTracksInfo() {
|
||||
return player.getCurrentTracksInfo();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackSelectionParameters getTrackSelectionParameters() {
|
||||
return player.getTrackSelectionParameters();
|
||||
@ -645,6 +650,11 @@ public class ForwardingPlayer implements Player {
|
||||
eventListener.onTracksChanged(trackGroups, trackSelections);
|
||||
}
|
||||
|
||||
@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,10 +119,22 @@ 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.
|
||||
*
|
||||
@ -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();
|
||||
|
||||
/**
|
||||
|
@ -0,0 +1,300 @@
|
||||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.android.exoplayer2;
|
||||
|
||||
import static com.google.android.exoplayer2.util.Assertions.checkArgument;
|
||||
import static com.google.android.exoplayer2.util.Assertions.checkNotNull;
|
||||
import static com.google.android.exoplayer2.util.BundleableUtil.fromBundleNullableList;
|
||||
import static com.google.android.exoplayer2.util.BundleableUtil.fromNullableBundle;
|
||||
import static com.google.android.exoplayer2.util.BundleableUtil.toBundleArrayList;
|
||||
|
||||
import android.os.Bundle;
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.source.TrackGroup;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelectionParameters;
|
||||
import com.google.common.base.MoreObjects;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.primitives.Booleans;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/** Immutable information ({@link TrackGroupInfo}) about tracks. */
|
||||
public final class TracksInfo implements Bundleable {
|
||||
/**
|
||||
* Information about tracks in a {@link TrackGroup}: their {@link C.TrackType}, if their format is
|
||||
* supported by the player and if they are selected for playback.
|
||||
*/
|
||||
public static final class TrackGroupInfo implements Bundleable {
|
||||
private final TrackGroup trackGroup;
|
||||
@C.FormatSupport private final int[] trackSupport;
|
||||
private final @C.TrackType int trackType;
|
||||
private final boolean[] trackSelected;
|
||||
|
||||
/**
|
||||
* Constructs a TrackGroupInfo.
|
||||
*
|
||||
* @param trackGroup The {@link TrackGroup} described.
|
||||
* @param trackSupport The {@link C.FormatSupport} of each track in the {@code trackGroup}.
|
||||
* @param trackType The {@link C.TrackType} of the tracks in the {@code trackGroup}.
|
||||
* @param tracksSelected Whether a track is selected for each track in {@code trackGroup}.
|
||||
*/
|
||||
public TrackGroupInfo(
|
||||
TrackGroup trackGroup,
|
||||
@C.FormatSupport int[] trackSupport,
|
||||
@C.TrackType int trackType,
|
||||
boolean[] tracksSelected) {
|
||||
int length = trackGroup.length;
|
||||
checkArgument(length == trackSupport.length && length == tracksSelected.length);
|
||||
this.trackGroup = trackGroup;
|
||||
this.trackSupport = trackSupport.clone();
|
||||
this.trackType = trackType;
|
||||
this.trackSelected = tracksSelected.clone();
|
||||
}
|
||||
|
||||
/** Returns the {@link TrackGroup} described by this {@code TrackGroupInfo}. */
|
||||
public TrackGroup getTrackGroup() {
|
||||
return trackGroup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the level of support for a track in a {@link TrackGroup}.
|
||||
*
|
||||
* @param trackIndex The index of the track in the {@link TrackGroup}.
|
||||
* @return The {@link C.FormatSupport} of the track.
|
||||
*/
|
||||
@C.FormatSupport
|
||||
public int getTrackSupport(int trackIndex) {
|
||||
return trackSupport[trackIndex];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if a track in a {@link TrackGroup} is supported for playback.
|
||||
*
|
||||
* @param trackIndex The index of the track in the {@link TrackGroup}.
|
||||
* @return True if the track's format can be played, false otherwise.
|
||||
*/
|
||||
public boolean isTrackSupported(int trackIndex) {
|
||||
return trackSupport[trackIndex] == C.FORMAT_HANDLED;
|
||||
}
|
||||
|
||||
/** Returns if at least one track in a {@link TrackGroup} is selected for playback. */
|
||||
public boolean isSelected() {
|
||||
return Booleans.contains(trackSelected, true);
|
||||
}
|
||||
|
||||
/** Returns if at least one track in a {@link TrackGroup} is supported. */
|
||||
public boolean isSupported() {
|
||||
for (int i = 0; i < trackSupport.length; i++) {
|
||||
if (isTrackSupported(i)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if a track in a {@link TrackGroup} is selected for playback.
|
||||
*
|
||||
* <p>Multiple tracks of a track group may be selected, in which case the the active one
|
||||
* (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}.
|
||||
*
|
||||
* @param trackIndex The index of the track in the {@link TrackGroup}.
|
||||
* @return true if the track is selected, false otherwise.
|
||||
*/
|
||||
public boolean isTrackSelected(int trackIndex) {
|
||||
return trackSelected[trackIndex];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link C.TrackType} of the tracks in the {@link TrackGroup}. Tracks in a group
|
||||
* are all of the same type.
|
||||
*/
|
||||
public @C.TrackType int getTrackType() {
|
||||
return trackType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (other == null || getClass() != other.getClass()) {
|
||||
return false;
|
||||
}
|
||||
TrackGroupInfo that = (TrackGroupInfo) other;
|
||||
return trackType == that.trackType
|
||||
&& trackGroup.equals(that.trackGroup)
|
||||
&& Arrays.equals(trackSupport, that.trackSupport)
|
||||
&& Arrays.equals(trackSelected, that.trackSelected);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = trackGroup.hashCode();
|
||||
result = 31 * result + Arrays.hashCode(trackSupport);
|
||||
result = 31 * result + trackType;
|
||||
result = 31 * result + Arrays.hashCode(trackSelected);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Bundleable implementation.
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({
|
||||
FIELD_TRACK_GROUP,
|
||||
FIELD_TRACK_SUPPORT,
|
||||
FIELD_TRACK_TYPE,
|
||||
FIELD_TRACK_SELECTED,
|
||||
})
|
||||
private @interface FieldNumber {}
|
||||
|
||||
private static final int FIELD_TRACK_GROUP = 0;
|
||||
private static final int FIELD_TRACK_SUPPORT = 1;
|
||||
private static final int FIELD_TRACK_TYPE = 2;
|
||||
private static final int FIELD_TRACK_SELECTED = 3;
|
||||
|
||||
@Override
|
||||
public Bundle toBundle() {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putBundle(keyForField(FIELD_TRACK_GROUP), trackGroup.toBundle());
|
||||
bundle.putIntArray(keyForField(FIELD_TRACK_SUPPORT), trackSupport);
|
||||
bundle.putInt(keyForField(FIELD_TRACK_TYPE), trackType);
|
||||
bundle.putBooleanArray(keyForField(FIELD_TRACK_SELECTED), trackSelected);
|
||||
return bundle;
|
||||
}
|
||||
|
||||
/** Object that can restores a {@code TracksInfo} from a {@link Bundle}. */
|
||||
public static final Creator<TrackGroupInfo> CREATOR =
|
||||
bundle -> {
|
||||
TrackGroup trackGroup =
|
||||
fromNullableBundle(
|
||||
TrackGroup.CREATOR, bundle.getBundle(keyForField(FIELD_TRACK_GROUP)));
|
||||
checkNotNull(trackGroup); // Can't create a trackGroup info without a trackGroup
|
||||
@C.FormatSupport
|
||||
final int[] trackSupport =
|
||||
MoreObjects.firstNonNull(
|
||||
bundle.getIntArray(keyForField(FIELD_TRACK_SUPPORT)), new int[trackGroup.length]);
|
||||
@C.TrackType
|
||||
int trackType = bundle.getInt(keyForField(FIELD_TRACK_TYPE), C.TRACK_TYPE_UNKNOWN);
|
||||
boolean[] selected =
|
||||
MoreObjects.firstNonNull(
|
||||
bundle.getBooleanArray(keyForField(FIELD_TRACK_SELECTED)),
|
||||
new boolean[trackGroup.length]);
|
||||
return new TrackGroupInfo(trackGroup, trackSupport, trackType, selected);
|
||||
};
|
||||
|
||||
private static String keyForField(@FieldNumber int field) {
|
||||
return Integer.toString(field, Character.MAX_RADIX);
|
||||
}
|
||||
}
|
||||
|
||||
private final ImmutableList<TrackGroupInfo> trackGroupInfos;
|
||||
|
||||
/** An empty {@code TrackInfo} containing no {@link TrackGroupInfo}. */
|
||||
public static final TracksInfo EMPTY = new TracksInfo(ImmutableList.of());
|
||||
|
||||
/** Constructs {@code TracksInfo} from the provided {@link TrackGroupInfo}. */
|
||||
public TracksInfo(List<TrackGroupInfo> trackGroupInfos) {
|
||||
this.trackGroupInfos = ImmutableList.copyOf(trackGroupInfos);
|
||||
}
|
||||
|
||||
/** Returns the {@link TrackGroupInfo TrackGroupInfos}, describing each {@link TrackGroup}. */
|
||||
public ImmutableList<TrackGroupInfo> getTrackGroupInfos() {
|
||||
return trackGroupInfos;
|
||||
}
|
||||
|
||||
/** Returns if there is at least one track of type {@code trackType} but none are supported. */
|
||||
public boolean isTypeSupportedOrEmpty(@C.TrackType int trackType) {
|
||||
boolean supported = true;
|
||||
for (int i = 0; i < trackGroupInfos.size(); i++) {
|
||||
if (trackGroupInfos.get(i).trackType == trackType) {
|
||||
if (trackGroupInfos.get(i).isSupported()) {
|
||||
return true;
|
||||
} else {
|
||||
supported = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return supported;
|
||||
}
|
||||
|
||||
/** Returns if at least one track of the type {@code trackType} is selected for playback. */
|
||||
public boolean isTypeSelected(@C.TrackType int trackType) {
|
||||
for (int i = 0; i < trackGroupInfos.size(); i++) {
|
||||
TrackGroupInfo trackGroupInfo = trackGroupInfos.get(i);
|
||||
if (trackGroupInfo.isSelected() && trackGroupInfo.getTrackType() == trackType) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object other) {
|
||||
if (this == other) {
|
||||
return true;
|
||||
}
|
||||
if (other == null || getClass() != other.getClass()) {
|
||||
return false;
|
||||
}
|
||||
TracksInfo that = (TracksInfo) other;
|
||||
return trackGroupInfos.equals(that.trackGroupInfos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return trackGroupInfos.hashCode();
|
||||
}
|
||||
// Bundleable implementation.
|
||||
|
||||
@Documented
|
||||
@Retention(RetentionPolicy.SOURCE)
|
||||
@IntDef({
|
||||
FIELD_TRACK_GROUP_INFOS,
|
||||
})
|
||||
private @interface FieldNumber {}
|
||||
|
||||
private static final int FIELD_TRACK_GROUP_INFOS = 0;
|
||||
|
||||
@Override
|
||||
public Bundle toBundle() {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putParcelableArrayList(
|
||||
keyForField(FIELD_TRACK_GROUP_INFOS), toBundleArrayList(trackGroupInfos));
|
||||
return bundle;
|
||||
}
|
||||
|
||||
/** Object that can restore a {@code TracksInfo} from a {@link Bundle}. */
|
||||
public static final Creator<TracksInfo> CREATOR =
|
||||
bundle -> {
|
||||
List<TrackGroupInfo> trackGroupInfos =
|
||||
fromBundleNullableList(
|
||||
TrackGroupInfo.CREATOR,
|
||||
bundle.getParcelableArrayList(keyForField(FIELD_TRACK_GROUP_INFOS)),
|
||||
/* defaultValue= */ ImmutableList.of());
|
||||
return new TracksInfo(trackGroupInfos);
|
||||
};
|
||||
|
||||
private static String keyForField(@FieldNumber int field) {
|
||||
return Integer.toString(field, Character.MAX_RADIX);
|
||||
}
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* 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();
|
||||
@ -951,6 +953,11 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||
return new TrackSelectionArray(playbackInfo.trackSelectorResult.selections);
|
||||
}
|
||||
|
||||
@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;
|
||||
|
@ -1456,6 +1456,12 @@ public class SimpleExoPlayer extends BasePlayer
|
||||
return player.getCurrentTrackSelections();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TracksInfo getCurrentTracksInfo() {
|
||||
verifyApplicationThread();
|
||||
return player.getCurrentTracksInfo();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackSelectionParameters getTrackSelectionParameters() {
|
||||
verifyApplicationThread();
|
||||
|
@ -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,10 +676,20 @@ 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.
|
||||
*
|
||||
|
@ -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(
|
||||
@ -562,17 +559,6 @@ public final class ExoPlayerTestRunner implements Player.Listener, ActionSchedul
|
||||
assertThat(playbackStates).containsExactlyElementsIn(states).inOrder();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
@ -656,11 +642,6 @@ public final class ExoPlayerTestRunner implements Player.Listener, ActionSchedul
|
||||
mediaItemTransitionReasons.add(reason);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
|
||||
this.trackGroups = trackGroups;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlaybackStateChanged(@Player.State int playbackState) {
|
||||
playbackStates.add(playbackState);
|
||||
|
@ -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;
|
||||
@ -463,6 +464,11 @@ public class StubExoPlayer extends BasePlayer implements ExoPlayer {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TracksInfo getCurrentTracksInfo() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TrackSelectionParameters getTrackSelectionParameters() {
|
||||
throw new UnsupportedOperationException();
|
||||
|
Loading…
x
Reference in New Issue
Block a user