Commit fbccdf59 by andrewlewis Committed by Oliver Woodman

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
parent 03b0d9d4
......@@ -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 ###
......
......@@ -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,13 +52,15 @@ 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,
DefaultDrmSessionManager.EventListener {
/** 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";
private static final int MAX_TIMELINE_ITEM_LINES = 3;
......@@ -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
......
......@@ -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);
}
......
......@@ -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);
}
......
......@@ -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,9 +192,25 @@ 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.
}
}
}
......@@ -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) {
......@@ -375,20 +372,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.
*/
private interface AdMediaSourceFactory {
......@@ -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
......
......@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment