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.source; 17 18 import android.os.Handler; 19 import androidx.annotation.Nullable; 20 import com.google.android.exoplayer2.C; 21 import com.google.android.exoplayer2.Timeline; 22 import com.google.android.exoplayer2.drm.DrmSessionEventListener; 23 import com.google.android.exoplayer2.upstream.Allocator; 24 import com.google.android.exoplayer2.upstream.TransferListener; 25 import java.io.IOException; 26 27 /** 28 * Defines and provides media to be played by an {@link com.google.android.exoplayer2.ExoPlayer}. A 29 * MediaSource has two main responsibilities: 30 * 31 * <ul> 32 * <li>To provide the player with a {@link Timeline} defining the structure of its media, and to 33 * provide a new timeline whenever the structure of the media changes. The MediaSource 34 * provides these timelines by calling {@link MediaSourceCaller#onSourceInfoRefreshed} on the 35 * {@link MediaSourceCaller}s passed to {@link #prepareSource(MediaSourceCaller, 36 * TransferListener)}. 37 * <li>To provide {@link MediaPeriod} instances for the periods in its timeline. MediaPeriods are 38 * obtained by calling {@link #createPeriod(MediaPeriodId, Allocator, long)}, and provide a 39 * way for the player to load and read the media. 40 * </ul> 41 * 42 * All methods are called on the player's internal playback thread, as described in the {@link 43 * com.google.android.exoplayer2.ExoPlayer} Javadoc. They should not be called directly from 44 * application code. Instances can be re-used, but only for one {@link 45 * com.google.android.exoplayer2.ExoPlayer} instance simultaneously. 46 */ 47 public interface MediaSource { 48 49 /** A caller of media sources, which will be notified of source events. */ 50 interface MediaSourceCaller { 51 52 /** 53 * Called when the {@link Timeline} has been refreshed. 54 * 55 * <p>Called on the playback thread. 56 * 57 * @param source The {@link MediaSource} whose info has been refreshed. 58 * @param timeline The source's timeline. 59 */ onSourceInfoRefreshed(MediaSource source, Timeline timeline)60 void onSourceInfoRefreshed(MediaSource source, Timeline timeline); 61 } 62 63 /** Identifier for a {@link MediaPeriod}. */ 64 final class MediaPeriodId { 65 66 /** The unique id of the timeline period. */ 67 public final Object periodUid; 68 69 /** 70 * If the media period is in an ad group, the index of the ad group in the period. 71 * {@link C#INDEX_UNSET} otherwise. 72 */ 73 public final int adGroupIndex; 74 75 /** 76 * If the media period is in an ad group, the index of the ad in its ad group in the period. 77 * {@link C#INDEX_UNSET} otherwise. 78 */ 79 public final int adIndexInAdGroup; 80 81 /** 82 * The sequence number of the window in the buffered sequence of windows this media period is 83 * part of. {@link C#INDEX_UNSET} if the media period id is not part of a buffered sequence of 84 * windows. 85 */ 86 public final long windowSequenceNumber; 87 88 /** 89 * The index of the next ad group to which the media period's content is clipped, or {@link 90 * C#INDEX_UNSET} if there is no following ad group or if this media period is an ad. 91 */ 92 public final int nextAdGroupIndex; 93 94 /** 95 * Creates a media period identifier for a dummy period which is not part of a buffered sequence 96 * of windows. 97 * 98 * @param periodUid The unique id of the timeline period. 99 */ MediaPeriodId(Object periodUid)100 public MediaPeriodId(Object periodUid) { 101 this(periodUid, /* windowSequenceNumber= */ C.INDEX_UNSET); 102 } 103 104 /** 105 * Creates a media period identifier for the specified period in the timeline. 106 * 107 * @param periodUid The unique id of the timeline period. 108 * @param windowSequenceNumber The sequence number of the window in the buffered sequence of 109 * windows this media period is part of. 110 */ MediaPeriodId(Object periodUid, long windowSequenceNumber)111 public MediaPeriodId(Object periodUid, long windowSequenceNumber) { 112 this( 113 periodUid, 114 /* adGroupIndex= */ C.INDEX_UNSET, 115 /* adIndexInAdGroup= */ C.INDEX_UNSET, 116 windowSequenceNumber, 117 /* nextAdGroupIndex= */ C.INDEX_UNSET); 118 } 119 120 /** 121 * Creates a media period identifier for the specified clipped period in the timeline. 122 * 123 * @param periodUid The unique id of the timeline period. 124 * @param windowSequenceNumber The sequence number of the window in the buffered sequence of 125 * windows this media period is part of. 126 * @param nextAdGroupIndex The index of the next ad group to which the media period's content is 127 * clipped. 128 */ MediaPeriodId(Object periodUid, long windowSequenceNumber, int nextAdGroupIndex)129 public MediaPeriodId(Object periodUid, long windowSequenceNumber, int nextAdGroupIndex) { 130 this( 131 periodUid, 132 /* adGroupIndex= */ C.INDEX_UNSET, 133 /* adIndexInAdGroup= */ C.INDEX_UNSET, 134 windowSequenceNumber, 135 nextAdGroupIndex); 136 } 137 138 /** 139 * Creates a media period identifier that identifies an ad within an ad group at the specified 140 * timeline period. 141 * 142 * @param periodUid The unique id of the timeline period that contains the ad group. 143 * @param adGroupIndex The index of the ad group. 144 * @param adIndexInAdGroup The index of the ad in the ad group. 145 * @param windowSequenceNumber The sequence number of the window in the buffered sequence of 146 * windows this media period is part of. 147 */ MediaPeriodId( Object periodUid, int adGroupIndex, int adIndexInAdGroup, long windowSequenceNumber)148 public MediaPeriodId( 149 Object periodUid, int adGroupIndex, int adIndexInAdGroup, long windowSequenceNumber) { 150 this( 151 periodUid, 152 adGroupIndex, 153 adIndexInAdGroup, 154 windowSequenceNumber, 155 /* nextAdGroupIndex= */ C.INDEX_UNSET); 156 } 157 MediaPeriodId( Object periodUid, int adGroupIndex, int adIndexInAdGroup, long windowSequenceNumber, int nextAdGroupIndex)158 private MediaPeriodId( 159 Object periodUid, 160 int adGroupIndex, 161 int adIndexInAdGroup, 162 long windowSequenceNumber, 163 int nextAdGroupIndex) { 164 this.periodUid = periodUid; 165 this.adGroupIndex = adGroupIndex; 166 this.adIndexInAdGroup = adIndexInAdGroup; 167 this.windowSequenceNumber = windowSequenceNumber; 168 this.nextAdGroupIndex = nextAdGroupIndex; 169 } 170 171 /** Returns a copy of this period identifier but with {@code newPeriodUid} as its period uid. */ copyWithPeriodUid(Object newPeriodUid)172 public MediaPeriodId copyWithPeriodUid(Object newPeriodUid) { 173 return periodUid.equals(newPeriodUid) 174 ? this 175 : new MediaPeriodId( 176 newPeriodUid, adGroupIndex, adIndexInAdGroup, windowSequenceNumber, nextAdGroupIndex); 177 } 178 179 /** 180 * Returns whether this period identifier identifies an ad in an ad group in a period. 181 */ isAd()182 public boolean isAd() { 183 return adGroupIndex != C.INDEX_UNSET; 184 } 185 186 @Override equals(@ullable Object obj)187 public boolean equals(@Nullable Object obj) { 188 if (this == obj) { 189 return true; 190 } 191 if (obj == null || getClass() != obj.getClass()) { 192 return false; 193 } 194 195 MediaPeriodId periodId = (MediaPeriodId) obj; 196 return periodUid.equals(periodId.periodUid) 197 && adGroupIndex == periodId.adGroupIndex 198 && adIndexInAdGroup == periodId.adIndexInAdGroup 199 && windowSequenceNumber == periodId.windowSequenceNumber 200 && nextAdGroupIndex == periodId.nextAdGroupIndex; 201 } 202 203 @Override hashCode()204 public int hashCode() { 205 int result = 17; 206 result = 31 * result + periodUid.hashCode(); 207 result = 31 * result + adGroupIndex; 208 result = 31 * result + adIndexInAdGroup; 209 result = 31 * result + (int) windowSequenceNumber; 210 result = 31 * result + nextAdGroupIndex; 211 return result; 212 } 213 } 214 215 /** 216 * Adds a {@link MediaSourceEventListener} to the list of listeners which are notified of media 217 * source events. 218 * 219 * @param handler A handler on the which listener events will be posted. 220 * @param eventListener The listener to be added. 221 */ addEventListener(Handler handler, MediaSourceEventListener eventListener)222 void addEventListener(Handler handler, MediaSourceEventListener eventListener); 223 224 /** 225 * Removes a {@link MediaSourceEventListener} from the list of listeners which are notified of 226 * media source events. 227 * 228 * @param eventListener The listener to be removed. 229 */ removeEventListener(MediaSourceEventListener eventListener)230 void removeEventListener(MediaSourceEventListener eventListener); 231 232 /** 233 * Adds a {@link DrmSessionEventListener} to the list of listeners which are notified of DRM 234 * events for this media source. 235 * 236 * @param handler A handler on the which listener events will be posted. 237 * @param eventListener The listener to be added. 238 */ addDrmEventListener(Handler handler, DrmSessionEventListener eventListener)239 void addDrmEventListener(Handler handler, DrmSessionEventListener eventListener); 240 241 /** 242 * Removes a {@link DrmSessionEventListener} from the list of listeners which are notified of DRM 243 * events for this media source. 244 * 245 * @param eventListener The listener to be removed. 246 */ removeDrmEventListener(DrmSessionEventListener eventListener)247 void removeDrmEventListener(DrmSessionEventListener eventListener); 248 249 /** 250 * Returns the initial dummy timeline that is returned immediately when the real timeline is not 251 * yet known, or null to let the player create an initial timeline. 252 * 253 * <p>The initial timeline must use the same uids for windows and periods that the real timeline 254 * will use. It also must provide windows which are marked as dynamic to indicate that the window 255 * is expected to change when the real timeline arrives. 256 * 257 * <p>Any media source which has multiple windows should typically provide such an initial 258 * timeline to make sure the player reports the correct number of windows immediately. 259 */ 260 @Nullable getInitialTimeline()261 default Timeline getInitialTimeline() { 262 return null; 263 } 264 265 /** 266 * Returns true if the media source is guaranteed to never have zero or more than one window. 267 * 268 * <p>The default implementation returns {@code true}. 269 * 270 * @return true if the source has exactly one window. 271 */ isSingleWindow()272 default boolean isSingleWindow() { 273 return true; 274 } 275 276 /** Returns the tag set on the media source, or null if none was set. */ 277 @Nullable getTag()278 default Object getTag() { 279 return null; 280 } 281 282 /** 283 * Registers a {@link MediaSourceCaller}. Starts source preparation if needed and enables the 284 * source for the creation of {@link MediaPeriod MediaPerods}. 285 * 286 * <p>Should not be called directly from application code. 287 * 288 * <p>{@link MediaSourceCaller#onSourceInfoRefreshed(MediaSource, Timeline)} will be called once 289 * the source has a {@link Timeline}. 290 * 291 * <p>For each call to this method, a call to {@link #releaseSource(MediaSourceCaller)} is needed 292 * to remove the caller and to release the source if no longer required. 293 * 294 * @param caller The {@link MediaSourceCaller} to be registered. 295 * @param mediaTransferListener The transfer listener which should be informed of any media data 296 * transfers. May be null if no listener is available. Note that this listener should be only 297 * informed of transfers related to the media loads and not of auxiliary loads for manifests 298 * and other data. 299 */ prepareSource(MediaSourceCaller caller, @Nullable TransferListener mediaTransferListener)300 void prepareSource(MediaSourceCaller caller, @Nullable TransferListener mediaTransferListener); 301 302 /** 303 * Throws any pending error encountered while loading or refreshing source information. 304 * 305 * <p>Should not be called directly from application code. 306 * 307 * <p>Must only be called after {@link #prepareSource(MediaSourceCaller, TransferListener)}. 308 */ maybeThrowSourceInfoRefreshError()309 void maybeThrowSourceInfoRefreshError() throws IOException; 310 311 /** 312 * Enables the source for the creation of {@link MediaPeriod MediaPeriods}. 313 * 314 * <p>Should not be called directly from application code. 315 * 316 * <p>Must only be called after {@link #prepareSource(MediaSourceCaller, TransferListener)}. 317 * 318 * @param caller The {@link MediaSourceCaller} enabling the source. 319 */ enable(MediaSourceCaller caller)320 void enable(MediaSourceCaller caller); 321 322 /** 323 * Returns a new {@link MediaPeriod} identified by {@code periodId}. 324 * 325 * <p>Should not be called directly from application code. 326 * 327 * <p>Must only be called if the source is enabled. 328 * 329 * @param id The identifier of the period. 330 * @param allocator An {@link Allocator} from which to obtain media buffer allocations. 331 * @param startPositionUs The expected start position, in microseconds. 332 * @return A new {@link MediaPeriod}. 333 */ createPeriod(MediaPeriodId id, Allocator allocator, long startPositionUs)334 MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator, long startPositionUs); 335 336 /** 337 * Releases the period. 338 * 339 * <p>Should not be called directly from application code. 340 * 341 * @param mediaPeriod The period to release. 342 */ releasePeriod(MediaPeriod mediaPeriod)343 void releasePeriod(MediaPeriod mediaPeriod); 344 345 /** 346 * Disables the source for the creation of {@link MediaPeriod MediaPeriods}. The implementation 347 * should not hold onto limited resources used for the creation of media periods. 348 * 349 * <p>Should not be called directly from application code. 350 * 351 * <p>Must only be called after all {@link MediaPeriod MediaPeriods} previously created by {@link 352 * #createPeriod(MediaPeriodId, Allocator, long)} have been released by {@link 353 * #releasePeriod(MediaPeriod)}. 354 * 355 * @param caller The {@link MediaSourceCaller} disabling the source. 356 */ disable(MediaSourceCaller caller)357 void disable(MediaSourceCaller caller); 358 359 /** 360 * Unregisters a caller, and disables and releases the source if no longer required. 361 * 362 * <p>Should not be called directly from application code. 363 * 364 * <p>Must only be called if all created {@link MediaPeriod MediaPeriods} have been released by 365 * {@link #releasePeriod(MediaPeriod)}. 366 * 367 * @param caller The {@link MediaSourceCaller} to be unregistered. 368 */ releaseSource(MediaSourceCaller caller)369 void releaseSource(MediaSourceCaller caller); 370 } 371