• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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