1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.google.android.exoplayer2.trackselection; 17 18 import androidx.annotation.Nullable; 19 import com.google.android.exoplayer2.C; 20 import com.google.android.exoplayer2.Format; 21 import com.google.android.exoplayer2.source.TrackGroup; 22 import com.google.android.exoplayer2.source.chunk.MediaChunk; 23 import com.google.android.exoplayer2.source.chunk.MediaChunkIterator; 24 import com.google.android.exoplayer2.upstream.BandwidthMeter; 25 import java.util.List; 26 import org.checkerframework.checker.nullness.compatqual.NullableType; 27 28 /** 29 * A track selection consisting of a static subset of selected tracks belonging to a {@link 30 * TrackGroup}, and a possibly varying individual selected track from the subset. 31 * 32 * <p>Tracks belonging to the subset are exposed in decreasing bandwidth order. The individual 33 * selected track may change dynamically as a result of calling {@link #updateSelectedTrack(long, 34 * long, long, List, MediaChunkIterator[])} or {@link #evaluateQueueSize(long, List)}. This only 35 * happens between calls to {@link #enable()} and {@link #disable()}. 36 */ 37 public interface TrackSelection { 38 39 /** Contains of a subset of selected tracks belonging to a {@link TrackGroup}. */ 40 final class Definition { 41 /** The {@link TrackGroup} which tracks belong to. */ 42 public final TrackGroup group; 43 /** The indices of the selected tracks in {@link #group}. */ 44 public final int[] tracks; 45 /** The track selection reason. One of the {@link C} SELECTION_REASON_ constants. */ 46 public final int reason; 47 /** Optional data associated with this selection of tracks. */ 48 @Nullable public final Object data; 49 50 /** 51 * @param group The {@link TrackGroup}. Must not be null. 52 * @param tracks The indices of the selected tracks within the {@link TrackGroup}. Must not be 53 * null or empty. May be in any order. 54 */ Definition(TrackGroup group, int... tracks)55 public Definition(TrackGroup group, int... tracks) { 56 this(group, tracks, C.SELECTION_REASON_UNKNOWN, /* data= */ null); 57 } 58 59 /** 60 * @param group The {@link TrackGroup}. Must not be null. 61 * @param tracks The indices of the selected tracks within the {@link TrackGroup}. Must not be 62 * @param reason The track selection reason. One of the {@link C} SELECTION_REASON_ constants. 63 * @param data Optional data associated with this selection of tracks. 64 */ Definition(TrackGroup group, int[] tracks, int reason, @Nullable Object data)65 public Definition(TrackGroup group, int[] tracks, int reason, @Nullable Object data) { 66 this.group = group; 67 this.tracks = tracks; 68 this.reason = reason; 69 this.data = data; 70 } 71 } 72 73 /** 74 * Factory for {@link TrackSelection} instances. 75 */ 76 interface Factory { 77 78 /** 79 * Creates track selections for the provided {@link Definition Definitions}. 80 * 81 * <p>Implementations that create at most one adaptive track selection may use {@link 82 * TrackSelectionUtil#createTrackSelectionsForDefinitions}. 83 * 84 * @param definitions A {@link Definition} array. May include null values. 85 * @param bandwidthMeter A {@link BandwidthMeter} which can be used to select tracks. 86 * @return The created selections. Must have the same length as {@code definitions} and may 87 * include null values. 88 */ 89 @NullableType createTrackSelections( @ullableType Definition[] definitions, BandwidthMeter bandwidthMeter)90 TrackSelection[] createTrackSelections( 91 @NullableType Definition[] definitions, BandwidthMeter bandwidthMeter); 92 } 93 94 /** 95 * Enables the track selection. Dynamic changes via {@link #updateSelectedTrack(long, long, long, 96 * List, MediaChunkIterator[])} or {@link #evaluateQueueSize(long, List)} will only happen after 97 * this call. 98 * 99 * <p>This method may not be called when the track selection is already enabled. 100 */ enable()101 void enable(); 102 103 /** 104 * Disables this track selection. No further dynamic changes via {@link #updateSelectedTrack(long, 105 * long, long, List, MediaChunkIterator[])} or {@link #evaluateQueueSize(long, List)} will happen 106 * after this call. 107 * 108 * <p>This method may only be called when the track selection is already enabled. 109 */ disable()110 void disable(); 111 112 /** 113 * Returns the {@link TrackGroup} to which the selected tracks belong. 114 */ getTrackGroup()115 TrackGroup getTrackGroup(); 116 117 // Static subset of selected tracks. 118 119 /** 120 * Returns the number of tracks in the selection. 121 */ length()122 int length(); 123 124 /** 125 * Returns the format of the track at a given index in the selection. 126 * 127 * @param index The index in the selection. 128 * @return The format of the selected track. 129 */ getFormat(int index)130 Format getFormat(int index); 131 132 /** 133 * Returns the index in the track group of the track at a given index in the selection. 134 * 135 * @param index The index in the selection. 136 * @return The index of the selected track. 137 */ getIndexInTrackGroup(int index)138 int getIndexInTrackGroup(int index); 139 140 /** 141 * Returns the index in the selection of the track with the specified format. The format is 142 * located by identity so, for example, {@code selection.indexOf(selection.getFormat(index)) == 143 * index} even if multiple selected tracks have formats that contain the same values. 144 * 145 * @param format The format. 146 * @return The index in the selection, or {@link C#INDEX_UNSET} if the track with the specified 147 * format is not part of the selection. 148 */ indexOf(Format format)149 int indexOf(Format format); 150 151 /** 152 * Returns the index in the selection of the track with the specified index in the track group. 153 * 154 * @param indexInTrackGroup The index in the track group. 155 * @return The index in the selection, or {@link C#INDEX_UNSET} if the track with the specified 156 * index is not part of the selection. 157 */ indexOf(int indexInTrackGroup)158 int indexOf(int indexInTrackGroup); 159 160 // Individual selected track. 161 162 /** 163 * Returns the {@link Format} of the individual selected track. 164 */ getSelectedFormat()165 Format getSelectedFormat(); 166 167 /** 168 * Returns the index in the track group of the individual selected track. 169 */ getSelectedIndexInTrackGroup()170 int getSelectedIndexInTrackGroup(); 171 172 /** 173 * Returns the index of the selected track. 174 */ getSelectedIndex()175 int getSelectedIndex(); 176 177 /** 178 * Returns the reason for the current track selection. 179 */ getSelectionReason()180 int getSelectionReason(); 181 182 /** Returns optional data associated with the current track selection. */ getSelectionData()183 @Nullable Object getSelectionData(); 184 185 // Adaptation. 186 187 /** 188 * Called to notify the selection of the current playback speed. The playback speed may affect 189 * adaptive track selection. 190 * 191 * @param speed The playback speed. 192 */ onPlaybackSpeed(float speed)193 void onPlaybackSpeed(float speed); 194 195 /** 196 * Called to notify the selection of a position discontinuity. 197 * 198 * <p>This happens when the playback position jumps, e.g., as a result of a seek being performed. 199 */ onDiscontinuity()200 default void onDiscontinuity() {} 201 202 /** 203 * Updates the selected track for sources that load media in discrete {@link MediaChunk}s. 204 * 205 * <p>This method may only be called when the selection is enabled. 206 * 207 * @param playbackPositionUs The current playback position in microseconds. If playback of the 208 * period to which this track selection belongs has not yet started, the value will be the 209 * starting position in the period minus the duration of any media in previous periods still 210 * to be played. 211 * @param bufferedDurationUs The duration of media currently buffered from the current playback 212 * position, in microseconds. Note that the next load position can be calculated as {@code 213 * (playbackPositionUs + bufferedDurationUs)}. 214 * @param availableDurationUs The duration of media available for buffering from the current 215 * playback position, in microseconds, or {@link C#TIME_UNSET} if media can be buffered to the 216 * end of the current period. Note that if not set to {@link C#TIME_UNSET}, the position up to 217 * which media is available for buffering can be calculated as {@code (playbackPositionUs + 218 * availableDurationUs)}. 219 * @param queue The queue of already buffered {@link MediaChunk}s. Must not be modified. 220 * @param mediaChunkIterators An array of {@link MediaChunkIterator}s providing information about 221 * the sequence of upcoming media chunks for each track in the selection. All iterators start 222 * from the media chunk which will be loaded next if the respective track is selected. Note 223 * that this information may not be available for all tracks, and so some iterators may be 224 * empty. 225 */ updateSelectedTrack( long playbackPositionUs, long bufferedDurationUs, long availableDurationUs, List<? extends MediaChunk> queue, MediaChunkIterator[] mediaChunkIterators)226 void updateSelectedTrack( 227 long playbackPositionUs, 228 long bufferedDurationUs, 229 long availableDurationUs, 230 List<? extends MediaChunk> queue, 231 MediaChunkIterator[] mediaChunkIterators); 232 233 /** 234 * May be called periodically by sources that load media in discrete {@link MediaChunk}s and 235 * support discarding of buffered chunks in order to re-buffer using a different selected track. 236 * Returns the number of chunks that should be retained in the queue. 237 * <p> 238 * To avoid excessive re-buffering, implementations should normally return the size of the queue. 239 * An example of a case where a smaller value may be returned is if network conditions have 240 * improved dramatically, allowing chunks to be discarded and re-buffered in a track of 241 * significantly higher quality. Discarding chunks may allow faster switching to a higher quality 242 * track in this case. This method may only be called when the selection is enabled. 243 * 244 * @param playbackPositionUs The current playback position in microseconds. If playback of the 245 * period to which this track selection belongs has not yet started, the value will be the 246 * starting position in the period minus the duration of any media in previous periods still 247 * to be played. 248 * @param queue The queue of buffered {@link MediaChunk}s. Must not be modified. 249 * @return The number of chunks to retain in the queue. 250 */ evaluateQueueSize(long playbackPositionUs, List<? extends MediaChunk> queue)251 int evaluateQueueSize(long playbackPositionUs, List<? extends MediaChunk> queue); 252 253 /** 254 * Attempts to blacklist the track at the specified index in the selection, making it ineligible 255 * for selection by calls to {@link #updateSelectedTrack(long, long, long, List, 256 * MediaChunkIterator[])} for the specified period of time. Blacklisting will fail if all other 257 * tracks are currently blacklisted. If blacklisting the currently selected track, note that it 258 * will remain selected until the next call to {@link #updateSelectedTrack(long, long, long, List, 259 * MediaChunkIterator[])}. 260 * 261 * <p>This method may only be called when the selection is enabled. 262 * 263 * @param index The index of the track in the selection. 264 * @param blacklistDurationMs The duration of time for which the track should be blacklisted, in 265 * milliseconds. 266 * @return Whether blacklisting was successful. 267 */ blacklist(int index, long blacklistDurationMs)268 boolean blacklist(int index, long blacklistDurationMs); 269 } 270