Use AdaptiveMediaSourceEventListener for ExtractorMediaSource

This is a step towards harmonizing the MediaSource Builders and (potentially)
providing MediaSource factories.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=177783157
This commit is contained in:
andrewlewis 2017-12-04 01:18:58 -08:00 committed by Oliver Woodman
parent 03b0d9d46c
commit fbccdf594a
9 changed files with 753 additions and 400 deletions

View File

@ -27,6 +27,8 @@
* Add optional parameter to `Player.stop` to reset the player when stopping.
* Fix handling of playback parameters changes while paused when followed by a
seek.
* Use the same listener `MediaSourceEventListener` for all MediaSource
implementations.
### 2.6.0 ###

View File

@ -39,7 +39,6 @@ import com.google.android.exoplayer2.metadata.id3.PrivFrame;
import com.google.android.exoplayer2.metadata.id3.TextInformationFrame;
import com.google.android.exoplayer2.metadata.id3.UrlLinkFrame;
import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener;
import com.google.android.exoplayer2.source.ExtractorMediaSource;
import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.source.ads.AdsMediaSource;
@ -53,12 +52,14 @@ import java.io.IOException;
import java.text.NumberFormat;
import java.util.Locale;
/**
* Logs player events using {@link Log}.
*/
/* package */ final class EventLogger implements Player.EventListener, MetadataOutput,
AudioRendererEventListener, VideoRendererEventListener, AdaptiveMediaSourceEventListener,
ExtractorMediaSource.EventListener, AdsMediaSource.AdsListener,
/** Logs player events using {@link Log}. */
/* package */ final class EventLogger
implements Player.EventListener,
MetadataOutput,
AudioRendererEventListener,
VideoRendererEventListener,
AdaptiveMediaSourceEventListener,
AdsMediaSource.EventListener,
DefaultDrmSessionManager.EventListener {
private static final String TAG = "EventLogger";
@ -324,13 +325,6 @@ import java.util.Locale;
Log.d(TAG, "drmKeysLoaded [" + getSessionTimeString() + "]");
}
// ExtractorMediaSource.EventListener
@Override
public void onLoadError(IOException error) {
printInternalError("loadError", error);
}
// AdaptiveMediaSourceEventListener
@Override

View File

@ -52,8 +52,8 @@ public final class ImaAdsMediaSource implements MediaSource {
}
/**
* Constructs a new source that inserts ads linearly with the content specified by
* {@code contentMediaSource}.
* Constructs a new source that inserts ads linearly with the content specified by {@code
* contentMediaSource}.
*
* @param contentMediaSource The {@link MediaSource} providing the content to play.
* @param dataSourceFactory Factory for data sources used to load ad media.
@ -62,9 +62,13 @@ public final class ImaAdsMediaSource implements MediaSource {
* @param eventHandler A handler for events. May be null if delivery of events is not required.
* @param eventListener A listener of events. May be null if delivery of events is not required.
*/
public ImaAdsMediaSource(MediaSource contentMediaSource, DataSource.Factory dataSourceFactory,
ImaAdsLoader imaAdsLoader, ViewGroup adUiViewGroup, @Nullable Handler eventHandler,
@Nullable AdsMediaSource.AdsListener eventListener) {
public ImaAdsMediaSource(
MediaSource contentMediaSource,
DataSource.Factory dataSourceFactory,
ImaAdsLoader imaAdsLoader,
ViewGroup adUiViewGroup,
@Nullable Handler eventHandler,
@Nullable AdsMediaSource.EventListener eventListener) {
adsMediaSource = new AdsMediaSource(contentMediaSource, dataSourceFactory, imaAdsLoader,
adUiViewGroup, eventHandler, eventListener);
}

View File

@ -16,306 +16,39 @@
package com.google.android.exoplayer2.source;
import android.os.Handler;
import android.os.SystemClock;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.android.exoplayer2.util.Assertions;
import java.io.IOException;
import android.support.annotation.Nullable;
/**
* Interface for callbacks to be notified of adaptive {@link MediaSource} events.
*/
public interface AdaptiveMediaSourceEventListener {
/**
* Called when a load begins.
* Interface for callbacks to be notified of {@link MediaSource} events.
*
* @param dataSpec Defines the data being loaded.
* @param dataType One of the {@link C} {@code DATA_TYPE_*} constants defining the type of data
* being loaded.
* @param trackType One of the {@link C} {@code TRACK_TYPE_*} constants if the data corresponds
* to media of a specific type. {@link C#TRACK_TYPE_UNKNOWN} otherwise.
* @param trackFormat The format of the track to which the data belongs. Null if the data does
* not belong to a track.
* @param trackSelectionReason One of the {@link C} {@code SELECTION_REASON_*} constants if the
* data belongs to a track. {@link C#SELECTION_REASON_UNKNOWN} otherwise.
* @param trackSelectionData Optional data associated with the selection of the track to which the
* data belongs. Null if the data does not belong to a track.
* @param mediaStartTimeMs The start time of the media being loaded, or {@link C#TIME_UNSET} if
* the load is not for media data.
* @param mediaEndTimeMs The end time of the media being loaded, or {@link C#TIME_UNSET} if the
* load is not for media data.
* @param elapsedRealtimeMs The value of {@link SystemClock#elapsedRealtime} when the load began.
* @deprecated Use {@link MediaSourceEventListener}
*/
void onLoadStarted(DataSpec dataSpec, int dataType, int trackType, Format trackFormat,
int trackSelectionReason, Object trackSelectionData, long mediaStartTimeMs,
long mediaEndTimeMs, long elapsedRealtimeMs);
@Deprecated
public interface AdaptiveMediaSourceEventListener extends MediaSourceEventListener {
/**
* Called when a load ends.
*
* @param dataSpec Defines the data being loaded.
* @param dataType One of the {@link C} {@code DATA_TYPE_*} constants defining the type of data
* being loaded.
* @param trackType One of the {@link C} {@code TRACK_TYPE_*} constants if the data corresponds
* to media of a specific type. {@link C#TRACK_TYPE_UNKNOWN} otherwise.
* @param trackFormat The format of the track to which the data belongs. Null if the data does
* not belong to a track.
* @param trackSelectionReason One of the {@link C} {@code SELECTION_REASON_*} constants if the
* data belongs to a track. {@link C#SELECTION_REASON_UNKNOWN} otherwise.
* @param trackSelectionData Optional data associated with the selection of the track to which the
* data belongs. Null if the data does not belong to a track.
* @param mediaStartTimeMs The start time of the media being loaded, or {@link C#TIME_UNSET} if
* the load is not for media data.
* @param mediaEndTimeMs The end time of the media being loaded, or {@link C#TIME_UNSET} if the
* load is not for media data.
* @param elapsedRealtimeMs The value of {@link SystemClock#elapsedRealtime} when the load ended.
* @param loadDurationMs The duration of the load.
* @param bytesLoaded The number of bytes that were loaded.
*/
void onLoadCompleted(DataSpec dataSpec, int dataType, int trackType, Format trackFormat,
int trackSelectionReason, Object trackSelectionData, long mediaStartTimeMs,
long mediaEndTimeMs, long elapsedRealtimeMs, long loadDurationMs, long bytesLoaded);
/**
* Called when a load is canceled.
*
* @param dataSpec Defines the data being loaded.
* @param dataType One of the {@link C} {@code DATA_TYPE_*} constants defining the type of data
* being loaded.
* @param trackType One of the {@link C} {@code TRACK_TYPE_*} constants if the data corresponds
* to media of a specific type. {@link C#TRACK_TYPE_UNKNOWN} otherwise.
* @param trackFormat The format of the track to which the data belongs. Null if the data does
* not belong to a track.
* @param trackSelectionReason One of the {@link C} {@code SELECTION_REASON_*} constants if the
* data belongs to a track. {@link C#SELECTION_REASON_UNKNOWN} otherwise.
* @param trackSelectionData Optional data associated with the selection of the track to which the
* data belongs. Null if the data does not belong to a track.
* @param mediaStartTimeMs The start time of the media being loaded, or {@link C#TIME_UNSET} if
* the load is not for media data.
* @param mediaEndTimeMs The end time of the media being loaded, or {@link C#TIME_UNSET} if the
* load is not for media data.
* @param elapsedRealtimeMs The value of {@link SystemClock#elapsedRealtime} when the load was
* canceled.
* @param loadDurationMs The duration of the load up to the point at which it was canceled.
* @param bytesLoaded The number of bytes that were loaded prior to cancelation.
*/
void onLoadCanceled(DataSpec dataSpec, int dataType, int trackType, Format trackFormat,
int trackSelectionReason, Object trackSelectionData, long mediaStartTimeMs,
long mediaEndTimeMs, long elapsedRealtimeMs, long loadDurationMs, long bytesLoaded);
/**
* Called when a load error occurs.
* <p>
* The error may or may not have resulted in the load being canceled, as indicated by the
* {@code wasCanceled} parameter. If the load was canceled, {@link #onLoadCanceled} will
* <em>not</em> be called in addition to this method.
* <p>
* This method being called does not indicate that playback has failed, or that it will fail. The
* player may be able to recover from the error and continue. Hence applications should
* <em>not</em> implement this method to display a user visible error or initiate an application
* level retry ({@link Player.EventListener#onPlayerError} is the appropriate place to implement
* such behavior). This method is called to provide the application with an opportunity to log the
* error if it wishes to do so.
*
* @param dataSpec Defines the data being loaded.
* @param dataType One of the {@link C} {@code DATA_TYPE_*} constants defining the type of data
* being loaded.
* @param trackType One of the {@link C} {@code TRACK_TYPE_*} constants if the data corresponds
* to media of a specific type. {@link C#TRACK_TYPE_UNKNOWN} otherwise.
* @param trackFormat The format of the track to which the data belongs. Null if the data does
* not belong to a track.
* @param trackSelectionReason One of the {@link C} {@code SELECTION_REASON_*} constants if the
* data belongs to a track. {@link C#SELECTION_REASON_UNKNOWN} otherwise.
* @param trackSelectionData Optional data associated with the selection of the track to which the
* data belongs. Null if the data does not belong to a track.
* @param mediaStartTimeMs The start time of the media being loaded, or {@link C#TIME_UNSET} if
* the load is not for media data.
* @param mediaEndTimeMs The end time of the media being loaded, or {@link C#TIME_UNSET} if the
* load is not for media data.
* @param elapsedRealtimeMs The value of {@link SystemClock#elapsedRealtime} when the error
* occurred.
* @param loadDurationMs The duration of the load up to the point at which the error occurred.
* @param bytesLoaded The number of bytes that were loaded prior to the error.
* @param error The load error.
* @param wasCanceled Whether the load was canceled as a result of the error.
*/
void onLoadError(DataSpec dataSpec, int dataType, int trackType, Format trackFormat,
int trackSelectionReason, Object trackSelectionData, long mediaStartTimeMs,
long mediaEndTimeMs, long elapsedRealtimeMs, long loadDurationMs, long bytesLoaded,
IOException error, boolean wasCanceled);
/**
* Called when data is removed from the back of a media buffer, typically so that it can be
* re-buffered in a different format.
*
* @param trackType The type of the media. One of the {@link C} {@code TRACK_TYPE_*} constants.
* @param mediaStartTimeMs The start time of the media being discarded.
* @param mediaEndTimeMs The end time of the media being discarded.
*/
void onUpstreamDiscarded(int trackType, long mediaStartTimeMs, long mediaEndTimeMs);
/**
* Called when a downstream format change occurs (i.e. when the format of the media being read
* from one or more {@link SampleStream}s provided by the source changes).
*
* @param trackType The type of the media. One of the {@link C} {@code TRACK_TYPE_*} constants.
* @param trackFormat The format of the track to which the data belongs. Null if the data does
* not belong to a track.
* @param trackSelectionReason One of the {@link C} {@code SELECTION_REASON_*} constants if the
* data belongs to a track. {@link C#SELECTION_REASON_UNKNOWN} otherwise.
* @param trackSelectionData Optional data associated with the selection of the track to which the
* data belongs. Null if the data does not belong to a track.
* @param mediaTimeMs The media time at which the change occurred.
*/
void onDownstreamFormatChanged(int trackType, Format trackFormat, int trackSelectionReason,
Object trackSelectionData, long mediaTimeMs);
/**
* Dispatches events to a {@link AdaptiveMediaSourceEventListener}.
*/
final class EventDispatcher {
/** Dispatches events to a {@link MediaSourceEventListener}. */
final class EventDispatcher extends MediaSourceEventListener.EventDispatcher {
private final Handler handler;
private final AdaptiveMediaSourceEventListener listener;
private final long mediaTimeOffsetMs;
private final MediaSourceEventListener listener;
public EventDispatcher(Handler handler, AdaptiveMediaSourceEventListener listener) {
public EventDispatcher(@Nullable Handler handler, @Nullable MediaSourceEventListener listener) {
this(handler, listener, 0);
}
public EventDispatcher(Handler handler, AdaptiveMediaSourceEventListener listener,
public EventDispatcher(
@Nullable Handler handler,
@Nullable MediaSourceEventListener listener,
long mediaTimeOffsetMs) {
this.handler = listener != null ? Assertions.checkNotNull(handler) : null;
super(handler, listener, mediaTimeOffsetMs);
this.handler = handler;
this.listener = listener;
this.mediaTimeOffsetMs = mediaTimeOffsetMs;
}
public EventDispatcher copyWithMediaTimeOffsetMs(long mediaTimeOffsetMs) {
return new EventDispatcher(handler, listener, mediaTimeOffsetMs);
}
public void loadStarted(DataSpec dataSpec, int dataType, long elapsedRealtimeMs) {
loadStarted(dataSpec, dataType, C.TRACK_TYPE_UNKNOWN, null, C.SELECTION_REASON_UNKNOWN,
null, C.TIME_UNSET, C.TIME_UNSET, elapsedRealtimeMs);
}
public void loadStarted(final DataSpec dataSpec, final int dataType, final int trackType,
final Format trackFormat, final int trackSelectionReason, final Object trackSelectionData,
final long mediaStartTimeUs, final long mediaEndTimeUs, final long elapsedRealtimeMs) {
if (listener != null) {
handler.post(new Runnable() {
@Override
public void run() {
listener.onLoadStarted(dataSpec, dataType, trackType, trackFormat, trackSelectionReason,
trackSelectionData, adjustMediaTime(mediaStartTimeUs),
adjustMediaTime(mediaEndTimeUs), elapsedRealtimeMs);
}
});
}
}
public void loadCompleted(DataSpec dataSpec, int dataType, long elapsedRealtimeMs,
long loadDurationMs, long bytesLoaded) {
loadCompleted(dataSpec, dataType, C.TRACK_TYPE_UNKNOWN, null, C.SELECTION_REASON_UNKNOWN,
null, C.TIME_UNSET, C.TIME_UNSET, elapsedRealtimeMs, loadDurationMs, bytesLoaded);
}
public void loadCompleted(final DataSpec dataSpec, final int dataType, final int trackType,
final Format trackFormat, final int trackSelectionReason, final Object trackSelectionData,
final long mediaStartTimeUs, final long mediaEndTimeUs, final long elapsedRealtimeMs,
final long loadDurationMs, final long bytesLoaded) {
if (listener != null) {
handler.post(new Runnable() {
@Override
public void run() {
listener.onLoadCompleted(dataSpec, dataType, trackType, trackFormat,
trackSelectionReason, trackSelectionData, adjustMediaTime(mediaStartTimeUs),
adjustMediaTime(mediaEndTimeUs), elapsedRealtimeMs, loadDurationMs, bytesLoaded);
}
});
}
}
public void loadCanceled(DataSpec dataSpec, int dataType, long elapsedRealtimeMs,
long loadDurationMs, long bytesLoaded) {
loadCanceled(dataSpec, dataType, C.TRACK_TYPE_UNKNOWN, null, C.SELECTION_REASON_UNKNOWN,
null, C.TIME_UNSET, C.TIME_UNSET, elapsedRealtimeMs, loadDurationMs, bytesLoaded);
}
public void loadCanceled(final DataSpec dataSpec, final int dataType, final int trackType,
final Format trackFormat, final int trackSelectionReason, final Object trackSelectionData,
final long mediaStartTimeUs, final long mediaEndTimeUs, final long elapsedRealtimeMs,
final long loadDurationMs, final long bytesLoaded) {
if (listener != null) {
handler.post(new Runnable() {
@Override
public void run() {
listener.onLoadCanceled(dataSpec, dataType, trackType, trackFormat,
trackSelectionReason, trackSelectionData, adjustMediaTime(mediaStartTimeUs),
adjustMediaTime(mediaEndTimeUs), elapsedRealtimeMs, loadDurationMs, bytesLoaded);
}
});
}
}
public void loadError(DataSpec dataSpec, int dataType, long elapsedRealtimeMs,
long loadDurationMs, long bytesLoaded, IOException error, boolean wasCanceled) {
loadError(dataSpec, dataType, C.TRACK_TYPE_UNKNOWN, null, C.SELECTION_REASON_UNKNOWN,
null, C.TIME_UNSET, C.TIME_UNSET, elapsedRealtimeMs, loadDurationMs, bytesLoaded,
error, wasCanceled);
}
public void loadError(final DataSpec dataSpec, final int dataType, final int trackType,
final Format trackFormat, final int trackSelectionReason, final Object trackSelectionData,
final long mediaStartTimeUs, final long mediaEndTimeUs, final long elapsedRealtimeMs,
final long loadDurationMs, final long bytesLoaded, final IOException error,
final boolean wasCanceled) {
if (listener != null) {
handler.post(new Runnable() {
@Override
public void run() {
listener.onLoadError(dataSpec, dataType, trackType, trackFormat, trackSelectionReason,
trackSelectionData, adjustMediaTime(mediaStartTimeUs),
adjustMediaTime(mediaEndTimeUs), elapsedRealtimeMs, loadDurationMs, bytesLoaded,
error, wasCanceled);
}
});
}
}
public void upstreamDiscarded(final int trackType, final long mediaStartTimeUs,
final long mediaEndTimeUs) {
if (listener != null) {
handler.post(new Runnable() {
@Override
public void run() {
listener.onUpstreamDiscarded(trackType, adjustMediaTime(mediaStartTimeUs),
adjustMediaTime(mediaEndTimeUs));
}
});
}
}
public void downstreamFormatChanged(final int trackType, final Format trackFormat,
final int trackSelectionReason, final Object trackSelectionData,
final long mediaTimeUs) {
if (listener != null) {
handler.post(new Runnable() {
@Override
public void run() {
listener.onDownstreamFormatChanged(trackType, trackFormat, trackSelectionReason,
trackSelectionData, adjustMediaTime(mediaTimeUs));
}
});
}
}
private long adjustMediaTime(long mediaTimeUs) {
long mediaTimeMs = C.usToMs(mediaTimeUs);
return mediaTimeMs == C.TIME_UNSET ? C.TIME_UNSET : mediaTimeOffsetMs + mediaTimeMs;
public AdaptiveMediaSourceEventListener.EventDispatcher copyWithMediaTimeOffsetMs(
long mediaTimeOffsetMs) {
return new AdaptiveMediaSourceEventListener.EventDispatcher(
handler, listener, mediaTimeOffsetMs);
}
}

View File

@ -17,6 +17,7 @@ package com.google.android.exoplayer2.source;
import android.net.Uri;
import android.os.Handler;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.FormatHolder;
@ -28,6 +29,7 @@ import com.google.android.exoplayer2.extractor.ExtractorOutput;
import com.google.android.exoplayer2.extractor.PositionHolder;
import com.google.android.exoplayer2.extractor.SeekMap;
import com.google.android.exoplayer2.extractor.TrackOutput;
import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher;
import com.google.android.exoplayer2.source.SampleQueue.UpstreamFormatChangedListener;
import com.google.android.exoplayer2.trackselection.TrackSelection;
import com.google.android.exoplayer2.upstream.Allocator;
@ -74,11 +76,10 @@ import java.util.Arrays;
private final Uri uri;
private final DataSource dataSource;
private final int minLoadableRetryCount;
private final Handler eventHandler;
private final ExtractorMediaSource.EventListener eventListener;
private final EventDispatcher eventDispatcher;
private final Listener listener;
private final Allocator allocator;
private final String customCacheKey;
@Nullable private final String customCacheKey;
private final long continueLoadingCheckIntervalBytes;
private final Loader loader;
private final ExtractorHolder extractorHolder;
@ -117,8 +118,7 @@ import java.util.Arrays;
* @param dataSource The data source to read the media.
* @param extractors The extractors to use to read the data source.
* @param minLoadableRetryCount The minimum number of times to retry if a loading error occurs.
* @param eventHandler A handler for events. May be null if delivery of events is not required.
* @param eventListener A listener of events. May be null if delivery of events is not required.
* @param eventDispatcher A dispatcher to notify of events.
* @param listener A listener to notify when information about the period changes.
* @param allocator An {@link Allocator} from which to obtain media buffer allocations.
* @param customCacheKey A custom key that uniquely identifies the original stream. Used for cache
@ -126,15 +126,20 @@ import java.util.Arrays;
* @param continueLoadingCheckIntervalBytes The number of bytes that should be loaded between each
* invocation of {@link Callback#onContinueLoadingRequested(SequenceableLoader)}.
*/
public ExtractorMediaPeriod(Uri uri, DataSource dataSource, Extractor[] extractors,
int minLoadableRetryCount, Handler eventHandler,
ExtractorMediaSource.EventListener eventListener, Listener listener,
Allocator allocator, String customCacheKey, int continueLoadingCheckIntervalBytes) {
public ExtractorMediaPeriod(
Uri uri,
DataSource dataSource,
Extractor[] extractors,
int minLoadableRetryCount,
EventDispatcher eventDispatcher,
Listener listener,
Allocator allocator,
@Nullable String customCacheKey,
int continueLoadingCheckIntervalBytes) {
this.uri = uri;
this.dataSource = dataSource;
this.minLoadableRetryCount = minLoadableRetryCount;
this.eventHandler = eventHandler;
this.eventListener = eventListener;
this.eventDispatcher = eventDispatcher;
this.listener = listener;
this.allocator = allocator;
this.customCacheKey = customCacheKey;
@ -430,8 +435,22 @@ import java.util.Arrays;
public int onLoadError(ExtractingLoadable loadable, long elapsedRealtimeMs,
long loadDurationMs, IOException error) {
copyLengthFromLoader(loadable);
notifyLoadError(error);
if (isLoadableExceptionFatal(error)) {
boolean isErrorFatal = isLoadableExceptionFatal(error);
eventDispatcher.loadError(
loadable.dataSpec,
C.DATA_TYPE_MEDIA,
C.TRACK_TYPE_UNKNOWN,
/* trackFormat= */ null,
C.SELECTION_REASON_UNKNOWN,
/* trackSelectionData= */ null,
/* mediaStartTimeUs= */ 0,
durationUs,
elapsedRealtimeMs,
loadDurationMs,
loadable.bytesLoaded,
error,
/* wasCanceled= */ isErrorFatal);
if (isErrorFatal) {
return Loader.DONT_RETRY_FATAL;
}
int extractedSamplesCount = getExtractedSamplesCount();
@ -606,17 +625,6 @@ import java.util.Arrays;
return e instanceof UnrecognizedInputFormatException;
}
private void notifyLoadError(final IOException error) {
if (eventHandler != null && eventListener != null) {
eventHandler.post(new Runnable() {
@Override
public void run() {
eventListener.onLoadError(error);
}
});
}
}
private final class SampleStreamImpl implements SampleStream {
private final int track;
@ -663,7 +671,9 @@ import java.util.Arrays;
private boolean pendingExtractorSeek;
private long seekTimeUs;
private DataSpec dataSpec;
private long length;
private long bytesLoaded;
public ExtractingLoadable(Uri uri, DataSource dataSource, ExtractorHolder extractorHolder,
ConditionVariable loadCondition) {
@ -699,7 +709,8 @@ import java.util.Arrays;
ExtractorInput input = null;
try {
long position = positionHolder.position;
length = dataSource.open(new DataSpec(uri, position, C.LENGTH_UNSET, customCacheKey));
dataSpec = new DataSpec(uri, position, C.LENGTH_UNSET, customCacheKey);
length = dataSource.open(dataSpec);
if (length != C.LENGTH_UNSET) {
length += position;
}
@ -723,6 +734,7 @@ import java.util.Arrays;
result = Extractor.RESULT_CONTINUE;
} else if (input != null) {
positionHolder.position = input.getPosition();
bytesLoaded = positionHolder.position - dataSpec.absoluteStreamPosition;
}
Util.closeQuietly(dataSource);
}

View File

@ -17,14 +17,18 @@ package com.google.android.exoplayer2.source;
import android.net.Uri;
import android.os.Handler;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
import com.google.android.exoplayer2.extractor.Extractor;
import com.google.android.exoplayer2.extractor.ExtractorsFactory;
import com.google.android.exoplayer2.source.AdaptiveMediaSourceEventListener.EventDispatcher;
import com.google.android.exoplayer2.upstream.Allocator;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.android.exoplayer2.util.Assertions;
import java.io.IOException;
@ -40,10 +44,12 @@ import java.io.IOException;
* Note that the built-in extractors for AAC, MPEG PS/TS and FLV streams do not support seeking.
*/
public final class ExtractorMediaSource implements MediaSource, ExtractorMediaPeriod.Listener {
/**
* Listener of {@link ExtractorMediaSource} events.
*
* @deprecated Use {@link MediaSourceEventListener}.
*/
@Deprecated
public interface EventListener {
/**
@ -89,8 +95,7 @@ public final class ExtractorMediaSource implements MediaSource, ExtractorMediaPe
private final DataSource.Factory dataSourceFactory;
private final ExtractorsFactory extractorsFactory;
private final int minLoadableRetryCount;
private final Handler eventHandler;
private final EventListener eventListener;
private final EventDispatcher eventDispatcher;
private final String customCacheKey;
private final int continueLoadingCheckIntervalBytes;
@ -108,9 +113,9 @@ public final class ExtractorMediaSource implements MediaSource, ExtractorMediaPe
private ExtractorsFactory extractorsFactory;
private int minLoadableRetryCount;
private Handler eventHandler;
private EventListener eventListener;
private String customCacheKey;
@Nullable private Handler eventHandler;
@Nullable private MediaSourceEventListener eventListener;
@Nullable private String customCacheKey;
private int continueLoadingCheckIntervalBytes;
private boolean isBuildCalled;
@ -187,8 +192,24 @@ public final class ExtractorMediaSource implements MediaSource, ExtractorMediaPe
* @param eventHandler A handler for events.
* @param eventListener A listener of events.
* @return This builder.
* @deprecated Use {@link #setEventListener(Handler, MediaSourceEventListener)}.
*/
@Deprecated
public Builder setEventListener(Handler eventHandler, EventListener eventListener) {
this.eventHandler = eventHandler;
this.eventListener = eventListener == null ? null : new EventListenerWrapper(eventListener);
return this;
}
/**
* Sets the listener to respond to {@link ExtractorMediaSource} events and the handler to
* deliver these events.
*
* @param eventHandler A handler for events.
* @param eventListener A listener of events.
* @return This builder.
*/
public Builder setEventListener(Handler eventHandler, MediaSourceEventListener eventListener) {
this.eventHandler = eventHandler;
this.eventListener = eventListener;
return this;
@ -270,12 +291,31 @@ public final class ExtractorMediaSource implements MediaSource, ExtractorMediaPe
public ExtractorMediaSource(Uri uri, DataSource.Factory dataSourceFactory,
ExtractorsFactory extractorsFactory, int minLoadableRetryCount, Handler eventHandler,
EventListener eventListener, String customCacheKey, int continueLoadingCheckIntervalBytes) {
this(
uri,
dataSourceFactory,
extractorsFactory,
minLoadableRetryCount,
eventHandler,
eventListener == null ? null : new EventListenerWrapper(eventListener),
customCacheKey,
continueLoadingCheckIntervalBytes);
}
private ExtractorMediaSource(
Uri uri,
DataSource.Factory dataSourceFactory,
ExtractorsFactory extractorsFactory,
int minLoadableRetryCount,
@Nullable Handler eventHandler,
@Nullable MediaSourceEventListener eventListener,
@Nullable String customCacheKey,
int continueLoadingCheckIntervalBytes) {
this.uri = uri;
this.dataSourceFactory = dataSourceFactory;
this.extractorsFactory = extractorsFactory;
this.minLoadableRetryCount = minLoadableRetryCount;
this.eventHandler = eventHandler;
this.eventListener = eventListener;
this.eventDispatcher = new EventDispatcher(eventHandler, eventListener);
this.customCacheKey = customCacheKey;
this.continueLoadingCheckIntervalBytes = continueLoadingCheckIntervalBytes;
}
@ -294,9 +334,16 @@ public final class ExtractorMediaSource implements MediaSource, ExtractorMediaPe
@Override
public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) {
Assertions.checkArgument(id.periodIndex == 0);
return new ExtractorMediaPeriod(uri, dataSourceFactory.createDataSource(),
extractorsFactory.createExtractors(), minLoadableRetryCount, eventHandler, eventListener,
this, allocator, customCacheKey, continueLoadingCheckIntervalBytes);
return new ExtractorMediaPeriod(
uri,
dataSourceFactory.createDataSource(),
extractorsFactory.createExtractors(),
minLoadableRetryCount,
eventDispatcher,
this,
allocator,
customCacheKey,
continueLoadingCheckIntervalBytes);
}
@Override
@ -332,4 +379,94 @@ public final class ExtractorMediaSource implements MediaSource, ExtractorMediaPe
new SinglePeriodTimeline(timelineDurationUs, timelineIsSeekable, false), null);
}
/**
* Wraps a deprecated {@link EventListener}, invoking its callback from the equivalent callback in
* {@link MediaSourceEventListener}.
*/
private static final class EventListenerWrapper implements MediaSourceEventListener {
private final EventListener eventListener;
public EventListenerWrapper(EventListener eventListener) {
this.eventListener = Assertions.checkNotNull(eventListener);
}
@Override
public void onLoadStarted(
DataSpec dataSpec,
int dataType,
int trackType,
Format trackFormat,
int trackSelectionReason,
Object trackSelectionData,
long mediaStartTimeMs,
long mediaEndTimeMs,
long elapsedRealtimeMs) {
// Do nothing.
}
@Override
public void onLoadCompleted(
DataSpec dataSpec,
int dataType,
int trackType,
Format trackFormat,
int trackSelectionReason,
Object trackSelectionData,
long mediaStartTimeMs,
long mediaEndTimeMs,
long elapsedRealtimeMs,
long loadDurationMs,
long bytesLoaded) {
// Do nothing.
}
@Override
public void onLoadCanceled(
DataSpec dataSpec,
int dataType,
int trackType,
Format trackFormat,
int trackSelectionReason,
Object trackSelectionData,
long mediaStartTimeMs,
long mediaEndTimeMs,
long elapsedRealtimeMs,
long loadDurationMs,
long bytesLoaded) {
// Do nothing.
}
@Override
public void onLoadError(
DataSpec dataSpec,
int dataType,
int trackType,
Format trackFormat,
int trackSelectionReason,
Object trackSelectionData,
long mediaStartTimeMs,
long mediaEndTimeMs,
long elapsedRealtimeMs,
long loadDurationMs,
long bytesLoaded,
IOException error,
boolean wasCanceled) {
eventListener.onLoadError(error);
}
@Override
public void onUpstreamDiscarded(int trackType, long mediaStartTimeMs, long mediaEndTimeMs) {
// Do nothing.
}
@Override
public void onDownstreamFormatChanged(
int trackType,
Format trackFormat,
int trackSelectionReason,
Object trackSelectionData,
long mediaTimeMs) {
// Do nothing.
}
}
}

View File

@ -0,0 +1,487 @@
/*
* Copyright (C) 2017 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.source;
import android.os.Handler;
import android.os.SystemClock;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.upstream.DataSpec;
import com.google.android.exoplayer2.util.Assertions;
import java.io.IOException;
/** Interface for callbacks to be notified of {@link MediaSource} events. */
public interface MediaSourceEventListener {
/**
* Called when a load begins.
*
* @param dataSpec Defines the data being loaded.
* @param dataType One of the {@link C} {@code DATA_TYPE_*} constants defining the type of data
* being loaded.
* @param trackType One of the {@link C} {@code TRACK_TYPE_*} constants if the data corresponds to
* media of a specific type. {@link C#TRACK_TYPE_UNKNOWN} otherwise.
* @param trackFormat The format of the track to which the data belongs. Null if the data does not
* belong to a track.
* @param trackSelectionReason One of the {@link C} {@code SELECTION_REASON_*} constants if the
* data belongs to a track. {@link C#SELECTION_REASON_UNKNOWN} otherwise.
* @param trackSelectionData Optional data associated with the selection of the track to which the
* data belongs. Null if the data does not belong to a track.
* @param mediaStartTimeMs The start time of the media being loaded, or {@link C#TIME_UNSET} if
* the load is not for media data.
* @param mediaEndTimeMs The end time of the media being loaded, or {@link C#TIME_UNSET} if the
* load is not for media data.
* @param elapsedRealtimeMs The value of {@link SystemClock#elapsedRealtime} when the load began.
*/
void onLoadStarted(
DataSpec dataSpec,
int dataType,
int trackType,
Format trackFormat,
int trackSelectionReason,
Object trackSelectionData,
long mediaStartTimeMs,
long mediaEndTimeMs,
long elapsedRealtimeMs);
/**
* Called when a load ends.
*
* @param dataSpec Defines the data being loaded.
* @param dataType One of the {@link C} {@code DATA_TYPE_*} constants defining the type of data
* being loaded.
* @param trackType One of the {@link C} {@code TRACK_TYPE_*} constants if the data corresponds to
* media of a specific type. {@link C#TRACK_TYPE_UNKNOWN} otherwise.
* @param trackFormat The format of the track to which the data belongs. Null if the data does not
* belong to a track.
* @param trackSelectionReason One of the {@link C} {@code SELECTION_REASON_*} constants if the
* data belongs to a track. {@link C#SELECTION_REASON_UNKNOWN} otherwise.
* @param trackSelectionData Optional data associated with the selection of the track to which the
* data belongs. Null if the data does not belong to a track.
* @param mediaStartTimeMs The start time of the media being loaded, or {@link C#TIME_UNSET} if
* the load is not for media data.
* @param mediaEndTimeMs The end time of the media being loaded, or {@link C#TIME_UNSET} if the
* load is not for media data.
* @param elapsedRealtimeMs The value of {@link SystemClock#elapsedRealtime} when the load ended.
* @param loadDurationMs The duration of the load.
* @param bytesLoaded The number of bytes that were loaded.
*/
void onLoadCompleted(
DataSpec dataSpec,
int dataType,
int trackType,
Format trackFormat,
int trackSelectionReason,
Object trackSelectionData,
long mediaStartTimeMs,
long mediaEndTimeMs,
long elapsedRealtimeMs,
long loadDurationMs,
long bytesLoaded);
/**
* Called when a load is canceled.
*
* @param dataSpec Defines the data being loaded.
* @param dataType One of the {@link C} {@code DATA_TYPE_*} constants defining the type of data
* being loaded.
* @param trackType One of the {@link C} {@code TRACK_TYPE_*} constants if the data corresponds to
* media of a specific type. {@link C#TRACK_TYPE_UNKNOWN} otherwise.
* @param trackFormat The format of the track to which the data belongs. Null if the data does not
* belong to a track.
* @param trackSelectionReason One of the {@link C} {@code SELECTION_REASON_*} constants if the
* data belongs to a track. {@link C#SELECTION_REASON_UNKNOWN} otherwise.
* @param trackSelectionData Optional data associated with the selection of the track to which the
* data belongs. Null if the data does not belong to a track.
* @param mediaStartTimeMs The start time of the media being loaded, or {@link C#TIME_UNSET} if
* the load is not for media data.
* @param mediaEndTimeMs The end time of the media being loaded, or {@link C#TIME_UNSET} if the
* load is not for media data.
* @param elapsedRealtimeMs The value of {@link SystemClock#elapsedRealtime} when the load was
* canceled.
* @param loadDurationMs The duration of the load up to the point at which it was canceled.
* @param bytesLoaded The number of bytes that were loaded prior to cancelation.
*/
void onLoadCanceled(
DataSpec dataSpec,
int dataType,
int trackType,
Format trackFormat,
int trackSelectionReason,
Object trackSelectionData,
long mediaStartTimeMs,
long mediaEndTimeMs,
long elapsedRealtimeMs,
long loadDurationMs,
long bytesLoaded);
/**
* Called when a load error occurs.
*
* <p>The error may or may not have resulted in the load being canceled, as indicated by the
* {@code wasCanceled} parameter. If the load was canceled, {@link #onLoadCanceled} will
* <em>not</em> be called in addition to this method.
*
* <p>This method being called does not indicate that playback has failed, or that it will fail.
* The player may be able to recover from the error and continue. Hence applications should
* <em>not</em> implement this method to display a user visible error or initiate an application
* level retry ({@link Player.EventListener#onPlayerError} is the appropriate place to implement
* such behavior). This method is called to provide the application with an opportunity to log the
* error if it wishes to do so.
*
* @param dataSpec Defines the data being loaded.
* @param dataType One of the {@link C} {@code DATA_TYPE_*} constants defining the type of data
* being loaded.
* @param trackType One of the {@link C} {@code TRACK_TYPE_*} constants if the data corresponds to
* media of a specific type. {@link C#TRACK_TYPE_UNKNOWN} otherwise.
* @param trackFormat The format of the track to which the data belongs. Null if the data does not
* belong to a track.
* @param trackSelectionReason One of the {@link C} {@code SELECTION_REASON_*} constants if the
* data belongs to a track. {@link C#SELECTION_REASON_UNKNOWN} otherwise.
* @param trackSelectionData Optional data associated with the selection of the track to which the
* data belongs. Null if the data does not belong to a track.
* @param mediaStartTimeMs The start time of the media being loaded, or {@link C#TIME_UNSET} if
* the load is not for media data.
* @param mediaEndTimeMs The end time of the media being loaded, or {@link C#TIME_UNSET} if the
* load is not for media data.
* @param elapsedRealtimeMs The value of {@link SystemClock#elapsedRealtime} when the error
* occurred.
* @param loadDurationMs The duration of the load up to the point at which the error occurred.
* @param bytesLoaded The number of bytes that were loaded prior to the error.
* @param error The load error.
* @param wasCanceled Whether the load was canceled as a result of the error.
*/
void onLoadError(
DataSpec dataSpec,
int dataType,
int trackType,
Format trackFormat,
int trackSelectionReason,
Object trackSelectionData,
long mediaStartTimeMs,
long mediaEndTimeMs,
long elapsedRealtimeMs,
long loadDurationMs,
long bytesLoaded,
IOException error,
boolean wasCanceled);
/**
* Called when data is removed from the back of a media buffer, typically so that it can be
* re-buffered in a different format.
*
* @param trackType The type of the media. One of the {@link C} {@code TRACK_TYPE_*} constants.
* @param mediaStartTimeMs The start time of the media being discarded.
* @param mediaEndTimeMs The end time of the media being discarded.
*/
void onUpstreamDiscarded(int trackType, long mediaStartTimeMs, long mediaEndTimeMs);
/**
* Called when a downstream format change occurs (i.e. when the format of the media being read
* from one or more {@link SampleStream}s provided by the source changes).
*
* @param trackType The type of the media. One of the {@link C} {@code TRACK_TYPE_*} constants.
* @param trackFormat The format of the track to which the data belongs. Null if the data does not
* belong to a track.
* @param trackSelectionReason One of the {@link C} {@code SELECTION_REASON_*} constants if the
* data belongs to a track. {@link C#SELECTION_REASON_UNKNOWN} otherwise.
* @param trackSelectionData Optional data associated with the selection of the track to which the
* data belongs. Null if the data does not belong to a track.
* @param mediaTimeMs The media time at which the change occurred.
*/
void onDownstreamFormatChanged(
int trackType,
Format trackFormat,
int trackSelectionReason,
Object trackSelectionData,
long mediaTimeMs);
/** Dispatches events to a {@link MediaSourceEventListener}. */
class EventDispatcher {
@Nullable private final Handler handler;
@Nullable private final MediaSourceEventListener listener;
private final long mediaTimeOffsetMs;
public EventDispatcher(@Nullable Handler handler, @Nullable MediaSourceEventListener listener) {
this(handler, listener, 0);
}
public EventDispatcher(
@Nullable Handler handler,
@Nullable MediaSourceEventListener listener,
long mediaTimeOffsetMs) {
this.handler = listener != null ? Assertions.checkNotNull(handler) : null;
this.listener = listener;
this.mediaTimeOffsetMs = mediaTimeOffsetMs;
}
public void loadStarted(DataSpec dataSpec, int dataType, long elapsedRealtimeMs) {
loadStarted(
dataSpec,
dataType,
C.TRACK_TYPE_UNKNOWN,
null,
C.SELECTION_REASON_UNKNOWN,
null,
C.TIME_UNSET,
C.TIME_UNSET,
elapsedRealtimeMs);
}
public void loadStarted(
final DataSpec dataSpec,
final int dataType,
final int trackType,
final Format trackFormat,
final int trackSelectionReason,
final Object trackSelectionData,
final long mediaStartTimeUs,
final long mediaEndTimeUs,
final long elapsedRealtimeMs) {
if (listener != null && handler != null) {
handler.post(
new Runnable() {
@Override
public void run() {
listener.onLoadStarted(
dataSpec,
dataType,
trackType,
trackFormat,
trackSelectionReason,
trackSelectionData,
adjustMediaTime(mediaStartTimeUs),
adjustMediaTime(mediaEndTimeUs),
elapsedRealtimeMs);
}
});
}
}
public void loadCompleted(
DataSpec dataSpec,
int dataType,
long elapsedRealtimeMs,
long loadDurationMs,
long bytesLoaded) {
loadCompleted(
dataSpec,
dataType,
C.TRACK_TYPE_UNKNOWN,
null,
C.SELECTION_REASON_UNKNOWN,
null,
C.TIME_UNSET,
C.TIME_UNSET,
elapsedRealtimeMs,
loadDurationMs,
bytesLoaded);
}
public void loadCompleted(
final DataSpec dataSpec,
final int dataType,
final int trackType,
final Format trackFormat,
final int trackSelectionReason,
final Object trackSelectionData,
final long mediaStartTimeUs,
final long mediaEndTimeUs,
final long elapsedRealtimeMs,
final long loadDurationMs,
final long bytesLoaded) {
if (listener != null && handler != null) {
handler.post(
new Runnable() {
@Override
public void run() {
listener.onLoadCompleted(
dataSpec,
dataType,
trackType,
trackFormat,
trackSelectionReason,
trackSelectionData,
adjustMediaTime(mediaStartTimeUs),
adjustMediaTime(mediaEndTimeUs),
elapsedRealtimeMs,
loadDurationMs,
bytesLoaded);
}
});
}
}
public void loadCanceled(
DataSpec dataSpec,
int dataType,
long elapsedRealtimeMs,
long loadDurationMs,
long bytesLoaded) {
loadCanceled(
dataSpec,
dataType,
C.TRACK_TYPE_UNKNOWN,
null,
C.SELECTION_REASON_UNKNOWN,
null,
C.TIME_UNSET,
C.TIME_UNSET,
elapsedRealtimeMs,
loadDurationMs,
bytesLoaded);
}
public void loadCanceled(
final DataSpec dataSpec,
final int dataType,
final int trackType,
final Format trackFormat,
final int trackSelectionReason,
final Object trackSelectionData,
final long mediaStartTimeUs,
final long mediaEndTimeUs,
final long elapsedRealtimeMs,
final long loadDurationMs,
final long bytesLoaded) {
if (listener != null && handler != null) {
handler.post(
new Runnable() {
@Override
public void run() {
listener.onLoadCanceled(
dataSpec,
dataType,
trackType,
trackFormat,
trackSelectionReason,
trackSelectionData,
adjustMediaTime(mediaStartTimeUs),
adjustMediaTime(mediaEndTimeUs),
elapsedRealtimeMs,
loadDurationMs,
bytesLoaded);
}
});
}
}
public void loadError(
DataSpec dataSpec,
int dataType,
long elapsedRealtimeMs,
long loadDurationMs,
long bytesLoaded,
IOException error,
boolean wasCanceled) {
loadError(
dataSpec,
dataType,
C.TRACK_TYPE_UNKNOWN,
null,
C.SELECTION_REASON_UNKNOWN,
null,
C.TIME_UNSET,
C.TIME_UNSET,
elapsedRealtimeMs,
loadDurationMs,
bytesLoaded,
error,
wasCanceled);
}
public void loadError(
final DataSpec dataSpec,
final int dataType,
final int trackType,
final Format trackFormat,
final int trackSelectionReason,
final Object trackSelectionData,
final long mediaStartTimeUs,
final long mediaEndTimeUs,
final long elapsedRealtimeMs,
final long loadDurationMs,
final long bytesLoaded,
final IOException error,
final boolean wasCanceled) {
if (listener != null && handler != null) {
handler.post(
new Runnable() {
@Override
public void run() {
listener.onLoadError(
dataSpec,
dataType,
trackType,
trackFormat,
trackSelectionReason,
trackSelectionData,
adjustMediaTime(mediaStartTimeUs),
adjustMediaTime(mediaEndTimeUs),
elapsedRealtimeMs,
loadDurationMs,
bytesLoaded,
error,
wasCanceled);
}
});
}
}
public void upstreamDiscarded(
final int trackType, final long mediaStartTimeUs, final long mediaEndTimeUs) {
if (listener != null && handler != null) {
handler.post(
new Runnable() {
@Override
public void run() {
listener.onUpstreamDiscarded(
trackType, adjustMediaTime(mediaStartTimeUs), adjustMediaTime(mediaEndTimeUs));
}
});
}
}
public void downstreamFormatChanged(
final int trackType,
final Format trackFormat,
final int trackSelectionReason,
final Object trackSelectionData,
final long mediaTimeUs) {
if (listener != null && handler != null) {
handler.post(
new Runnable() {
@Override
public void run() {
listener.onDownstreamFormatChanged(
trackType,
trackFormat,
trackSelectionReason,
trackSelectionData,
adjustMediaTime(mediaTimeUs));
}
});
}
}
private long adjustMediaTime(long mediaTimeUs) {
long mediaTimeMs = C.usToMs(mediaTimeUs);
return mediaTimeMs == C.TIME_UNSET ? C.TIME_UNSET : mediaTimeOffsetMs + mediaTimeMs;
}
}
}

View File

@ -26,9 +26,9 @@ import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.source.DeferredMediaPeriod;
import com.google.android.exoplayer2.source.ExtractorMediaSource;
import com.google.android.exoplayer2.source.ExtractorMediaSource.EventListener;
import com.google.android.exoplayer2.source.MediaPeriod;
import com.google.android.exoplayer2.source.MediaSource;
import com.google.android.exoplayer2.source.MediaSourceEventListener;
import com.google.android.exoplayer2.upstream.Allocator;
import com.google.android.exoplayer2.upstream.DataSource;
import com.google.android.exoplayer2.util.Assertions;
@ -44,10 +44,8 @@ import java.util.Map;
*/
public final class AdsMediaSource implements MediaSource {
/**
* Listener for events relating to ad loading.
*/
public interface AdsListener {
/** Listener for ads media source events. */
public interface EventListener extends MediaSourceEventListener {
/**
* Called if there was an error loading ads. The media source will load the content without ads
@ -75,15 +73,13 @@ public final class AdsMediaSource implements MediaSource {
private final MediaSource contentMediaSource;
private final AdsLoader adsLoader;
private final ViewGroup adUiViewGroup;
@Nullable private final Handler eventHandler;
@Nullable private final EventListener eventListener;
private final Handler mainHandler;
private final ComponentListener componentListener;
private final AdMediaSourceFactory adMediaSourceFactory;
private final Map<MediaSource, List<DeferredMediaPeriod>> deferredMediaPeriodByAdMediaSource;
private final Timeline.Period period;
@Nullable
private final Handler eventHandler;
@Nullable
private final AdsListener eventListener;
private Handler playerHandler;
private ExoPlayer player;
@ -115,10 +111,10 @@ public final class AdsMediaSource implements MediaSource {
}
/**
* Constructs a new source that inserts ads linearly with the content specified by
* {@code contentMediaSource}.
* <p>
* Ad media is loaded using {@link ExtractorMediaSource}. If {@code eventListener} is
* Constructs a new source that inserts ads linearly with the content specified by {@code
* contentMediaSource}.
*
* <p>Ad media is loaded using {@link ExtractorMediaSource}. If {@code eventListener} is
* non-{@code null} it will be notified of both ad tag and ad media load errors.
*
* @param contentMediaSource The {@link MediaSource} providing the content to play.
@ -128,9 +124,13 @@ public final class AdsMediaSource implements MediaSource {
* @param eventHandler A handler for events. May be null if delivery of events is not required.
* @param eventListener A listener of events. May be null if delivery of events is not required.
*/
public AdsMediaSource(MediaSource contentMediaSource, DataSource.Factory dataSourceFactory,
AdsLoader adsLoader, ViewGroup adUiViewGroup, @Nullable Handler eventHandler,
@Nullable AdsListener eventListener) {
public AdsMediaSource(
MediaSource contentMediaSource,
DataSource.Factory dataSourceFactory,
AdsLoader adsLoader,
ViewGroup adUiViewGroup,
@Nullable Handler eventHandler,
@Nullable EventListener eventListener) {
this.contentMediaSource = contentMediaSource;
this.adsLoader = adsLoader;
this.adUiViewGroup = adUiViewGroup;
@ -186,7 +186,7 @@ public final class AdsMediaSource implements MediaSource {
if (adGroupMediaSources[adGroupIndex].length <= adIndexInAdGroup) {
Uri adUri = adPlaybackState.adUris[id.adGroupIndex][id.adIndexInAdGroup];
final MediaSource adMediaSource =
adMediaSourceFactory.createAdMediaSource(adUri, mainHandler, componentListener);
adMediaSourceFactory.createAdMediaSource(adUri, eventHandler, eventListener);
int oldAdCount = adGroupMediaSources[id.adGroupIndex].length;
if (adIndexInAdGroup >= oldAdCount) {
int adCount = adIndexInAdGroup + 1;
@ -306,11 +306,8 @@ public final class AdsMediaSource implements MediaSource {
}
}
/**
* Listener for component events. All methods are called on the main thread.
*/
private final class ComponentListener implements AdsLoader.EventListener,
AdMediaSourceLoadErrorListener {
/** Listener for component events. All methods are called on the main thread. */
private final class ComponentListener implements AdsLoader.EventListener {
@Override
public void onAdPlaybackState(final AdPlaybackState adPlaybackState) {
@ -374,20 +371,6 @@ public final class AdsMediaSource implements MediaSource {
}
/**
* Listener for errors while loading an ad {@link MediaSource}.
*/
private interface AdMediaSourceLoadErrorListener {
/**
* Called when an error occurs loading media data.
*
* @param error The load error.
*/
void onLoadError(IOException error);
}
/**
* Factory for {@link MediaSource}s for loading ad media.
*/
@ -397,15 +380,13 @@ public final class AdsMediaSource implements MediaSource {
* Creates a new {@link MediaSource} for loading the ad media with the specified {@code uri}.
*
* @param uri The URI of the ad.
* @param handler A handler for listener events.
* @param listener A listener for ad load errors. To have ad media source load errors notified
* via the ads media source's listener, call this listener's onLoadError method from your
* new media source's load error listener using the specified {@code handler}. Otherwise,
* this parameter can be ignored.
* @param handler A handler for listener events. May be null if delivery of events is not
* required.
* @param listener A listener for events. May be null if delivery of events is not required.
* @return The new media source.
*/
MediaSource createAdMediaSource(Uri uri, Handler handler,
AdMediaSourceLoadErrorListener listener);
MediaSource createAdMediaSource(
Uri uri, @Nullable Handler handler, @Nullable MediaSourceEventListener listener);
/**
* Returns the content types supported by media sources created by this factory. Each element
@ -427,15 +408,11 @@ public final class AdsMediaSource implements MediaSource {
}
@Override
public MediaSource createAdMediaSource(Uri uri, Handler handler,
final AdMediaSourceLoadErrorListener listener) {
return new ExtractorMediaSource.Builder(uri, dataSourceFactory).setEventListener(handler,
new EventListener() {
@Override
public void onLoadError(IOException error) {
listener.onLoadError(error);
}
}).build();
public MediaSource createAdMediaSource(
Uri uri, @Nullable Handler handler, @Nullable MediaSourceEventListener listener) {
return new ExtractorMediaSource.Builder(uri, dataSourceFactory)
.setEventListener(handler, listener)
.build();
}
@Override

View File

@ -17,6 +17,7 @@ package com.google.android.exoplayer2.upstream;
import android.net.Uri;
import android.support.annotation.IntDef;
import android.support.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.util.Assertions;
import java.lang.annotation.Retention;
@ -79,7 +80,7 @@ public final class DataSpec {
* A key that uniquely identifies the original stream. Used for cache indexing. May be null if the
* {@link DataSpec} is not intended to be used in conjunction with a cache.
*/
public final String key;
@Nullable public final String key;
/**
* Request flags. Currently {@link #FLAG_ALLOW_GZIP} and
* {@link #FLAG_ALLOW_CACHING_UNKNOWN_LENGTH} are the only supported flags.
@ -113,7 +114,7 @@ public final class DataSpec {
* @param length {@link #length}.
* @param key {@link #key}.
*/
public DataSpec(Uri uri, long absoluteStreamPosition, long length, String key) {
public DataSpec(Uri uri, long absoluteStreamPosition, long length, @Nullable String key) {
this(uri, absoluteStreamPosition, absoluteStreamPosition, length, key, 0);
}
@ -147,8 +148,8 @@ public final class DataSpec {
}
/**
* Construct a {@link DataSpec} where {@link #position} may differ from
* {@link #absoluteStreamPosition}.
* Construct a {@link DataSpec} where {@link #position} may differ from {@link
* #absoluteStreamPosition}.
*
* @param uri {@link #uri}.
* @param postBody {@link #postBody}.
@ -158,8 +159,14 @@ public final class DataSpec {
* @param key {@link #key}.
* @param flags {@link #flags}.
*/
public DataSpec(Uri uri, byte[] postBody, long absoluteStreamPosition, long position, long length,
String key, @Flags int flags) {
public DataSpec(
Uri uri,
byte[] postBody,
long absoluteStreamPosition,
long position,
long length,
@Nullable String key,
@Flags int flags) {
Assertions.checkArgument(absoluteStreamPosition >= 0);
Assertions.checkArgument(position >= 0);
Assertions.checkArgument(length > 0 || length == C.LENGTH_UNSET);