Fix nullness warning for MediaSource/MediaPeriod classes.

PiperOrigin-RevId: 249652301
This commit is contained in:
tonihei 2019-05-23 16:54:45 +01:00 committed by Toni
parent 14c46bc406
commit 3e990a3d24
10 changed files with 146 additions and 104 deletions

View File

@ -19,6 +19,7 @@ import android.util.Pair;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.util.Assertions;
/**
* Abstract base class for the concatenation of one or more {@link Timeline}s.
@ -35,6 +36,7 @@ import com.google.android.exoplayer2.Timeline;
* @param concatenatedUid UID of a period in a concatenated timeline.
* @return UID of the child timeline this period belongs to.
*/
@SuppressWarnings("nullness:return.type.incompatible")
public static Object getChildTimelineUidFromConcatenatedUid(Object concatenatedUid) {
return ((Pair<?, ?>) concatenatedUid).first;
}
@ -45,6 +47,7 @@ import com.google.android.exoplayer2.Timeline;
* @param concatenatedUid UID of a period in a concatenated timeline.
* @return UID of the period in the child timeline.
*/
@SuppressWarnings("nullness:return.type.incompatible")
public static Object getChildPeriodUidFromConcatenatedUid(Object concatenatedUid) {
return ((Pair<?, ?>) concatenatedUid).second;
}
@ -220,7 +223,9 @@ import com.google.android.exoplayer2.Timeline;
setIds);
period.windowIndex += firstWindowIndexInChild;
if (setIds) {
period.uid = getConcatenatedUid(getChildUidByChildIndex(childIndex), period.uid);
period.uid =
getConcatenatedUid(
getChildUidByChildIndex(childIndex), Assertions.checkNotNull(period.uid));
}
return period;
}

View File

@ -15,6 +15,7 @@
*/
package com.google.android.exoplayer2.source;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.FormatHolder;
@ -25,6 +26,7 @@ import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.Util;
import java.io.IOException;
import org.checkerframework.checker.nullness.compatqual.NullableType;
/**
* Wraps a {@link MediaPeriod} and clips its {@link SampleStream}s to provide a subsequence of their
@ -37,8 +39,8 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb
*/
public final MediaPeriod mediaPeriod;
private MediaPeriod.Callback callback;
private ClippingSampleStream[] sampleStreams;
@Nullable private MediaPeriod.Callback callback;
private @NullableType ClippingSampleStream[] sampleStreams;
private long pendingInitialDiscontinuityPositionUs;
/* package */ long startUs;
/* package */ long endUs;
@ -95,10 +97,14 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb
}
@Override
public long selectTracks(TrackSelection[] selections, boolean[] mayRetainStreamFlags,
SampleStream[] streams, boolean[] streamResetFlags, long positionUs) {
public long selectTracks(
@NullableType TrackSelection[] selections,
boolean[] mayRetainStreamFlags,
@NullableType SampleStream[] streams,
boolean[] streamResetFlags,
long positionUs) {
sampleStreams = new ClippingSampleStream[streams.length];
SampleStream[] childStreams = new SampleStream[streams.length];
@NullableType SampleStream[] childStreams = new SampleStream[streams.length];
for (int i = 0; i < streams.length; i++) {
sampleStreams[i] = (ClippingSampleStream) streams[i];
childStreams[i] = sampleStreams[i] != null ? sampleStreams[i].childStream : null;
@ -119,7 +125,7 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb
for (int i = 0; i < streams.length; i++) {
if (childStreams[i] == null) {
sampleStreams[i] = null;
} else if (streams[i] == null || sampleStreams[i].childStream != childStreams[i]) {
} else if (sampleStreams[i] == null || sampleStreams[i].childStream != childStreams[i]) {
sampleStreams[i] = new ClippingSampleStream(childStreams[i]);
}
streams[i] = sampleStreams[i];
@ -209,12 +215,12 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb
@Override
public void onPrepared(MediaPeriod mediaPeriod) {
callback.onPrepared(this);
Assertions.checkNotNull(callback).onPrepared(this);
}
@Override
public void onContinueLoadingRequested(MediaPeriod source) {
callback.onContinueLoadingRequested(this);
Assertions.checkNotNull(callback).onContinueLoadingRequested(this);
}
/* package */ boolean isPendingInitialDiscontinuity() {
@ -238,7 +244,8 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb
}
}
private static boolean shouldKeepInitialDiscontinuity(long startUs, TrackSelection[] selections) {
private static boolean shouldKeepInitialDiscontinuity(
long startUs, @NullableType TrackSelection[] selections) {
// If the clipping start position is non-zero, the clipping sample streams will adjust
// timestamps on buffers they read from the unclipped sample streams. These adjusted buffer
// timestamps can be negative, because sample streams provide buffers starting at a key-frame,
@ -300,7 +307,7 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb
}
int result = childStream.readData(formatHolder, buffer, requireFormat);
if (result == C.RESULT_FORMAT_READ) {
Format format = formatHolder.format;
Format format = Assertions.checkNotNull(formatHolder.format);
if (format.encoderDelay != 0 || format.encoderPadding != 0) {
// Clear gapless playback metadata if the start/end points don't match the media.
int encoderDelay = startUs != 0 ? 0 : format.encoderDelay;
@ -328,7 +335,5 @@ public final class ClippingMediaPeriod implements MediaPeriod, MediaPeriod.Callb
}
return childStream.skipData(positionUs);
}
}
}

View File

@ -15,6 +15,7 @@
*/
package com.google.android.exoplayer2.source;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
@ -86,9 +87,9 @@ public final class ClippingMediaSource extends CompositeMediaSource<Void> {
private final ArrayList<ClippingMediaPeriod> mediaPeriods;
private final Timeline.Window window;
private @Nullable Object manifest;
private ClippingTimeline clippingTimeline;
private IllegalClippingException clippingError;
@Nullable private Object manifest;
@Nullable private ClippingTimeline clippingTimeline;
@Nullable private IllegalClippingException clippingError;
private long periodStartUs;
private long periodEndUs;
@ -222,7 +223,7 @@ public final class ClippingMediaSource extends CompositeMediaSource<Void> {
Assertions.checkState(mediaPeriods.remove(mediaPeriod));
mediaSource.releasePeriod(((ClippingMediaPeriod) mediaPeriod).mediaPeriod);
if (mediaPeriods.isEmpty() && !allowDynamicClippingUpdates) {
refreshClippedTimeline(clippingTimeline.timeline);
refreshClippedTimeline(Assertions.checkNotNull(clippingTimeline).timeline);
}
}

View File

@ -15,6 +15,8 @@
*/
package com.google.android.exoplayer2.source;
import static com.google.android.exoplayer2.util.Util.castNonNull;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.SeekParameters;
@ -22,6 +24,7 @@ import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
import com.google.android.exoplayer2.trackselection.TrackSelection;
import com.google.android.exoplayer2.upstream.Allocator;
import java.io.IOException;
import org.checkerframework.checker.nullness.compatqual.NullableType;
/**
* Media period that wraps a media source and defers calling its {@link
@ -47,10 +50,10 @@ public final class DeferredMediaPeriod implements MediaPeriod, MediaPeriod.Callb
private final Allocator allocator;
private MediaPeriod mediaPeriod;
private Callback callback;
@Nullable private MediaPeriod mediaPeriod;
@Nullable private Callback callback;
private long preparePositionUs;
private @Nullable PrepareErrorListener listener;
@Nullable private PrepareErrorListener listener;
private boolean notifiedPrepareError;
private long preparePositionOverrideUs;
@ -150,53 +153,57 @@ public final class DeferredMediaPeriod implements MediaPeriod, MediaPeriod.Callb
@Override
public TrackGroupArray getTrackGroups() {
return mediaPeriod.getTrackGroups();
return castNonNull(mediaPeriod).getTrackGroups();
}
@Override
public long selectTracks(TrackSelection[] selections, boolean[] mayRetainStreamFlags,
SampleStream[] streams, boolean[] streamResetFlags, long positionUs) {
public long selectTracks(
@NullableType TrackSelection[] selections,
boolean[] mayRetainStreamFlags,
@NullableType SampleStream[] streams,
boolean[] streamResetFlags,
long positionUs) {
if (preparePositionOverrideUs != C.TIME_UNSET && positionUs == preparePositionUs) {
positionUs = preparePositionOverrideUs;
preparePositionOverrideUs = C.TIME_UNSET;
}
return mediaPeriod.selectTracks(selections, mayRetainStreamFlags, streams, streamResetFlags,
positionUs);
return castNonNull(mediaPeriod)
.selectTracks(selections, mayRetainStreamFlags, streams, streamResetFlags, positionUs);
}
@Override
public void discardBuffer(long positionUs, boolean toKeyframe) {
mediaPeriod.discardBuffer(positionUs, toKeyframe);
castNonNull(mediaPeriod).discardBuffer(positionUs, toKeyframe);
}
@Override
public long readDiscontinuity() {
return mediaPeriod.readDiscontinuity();
return castNonNull(mediaPeriod).readDiscontinuity();
}
@Override
public long getBufferedPositionUs() {
return mediaPeriod.getBufferedPositionUs();
return castNonNull(mediaPeriod).getBufferedPositionUs();
}
@Override
public long seekToUs(long positionUs) {
return mediaPeriod.seekToUs(positionUs);
return castNonNull(mediaPeriod).seekToUs(positionUs);
}
@Override
public long getAdjustedSeekPositionUs(long positionUs, SeekParameters seekParameters) {
return mediaPeriod.getAdjustedSeekPositionUs(positionUs, seekParameters);
return castNonNull(mediaPeriod).getAdjustedSeekPositionUs(positionUs, seekParameters);
}
@Override
public long getNextLoadPositionUs() {
return mediaPeriod.getNextLoadPositionUs();
return castNonNull(mediaPeriod).getNextLoadPositionUs();
}
@Override
public void reevaluateBuffer(long positionUs) {
mediaPeriod.reevaluateBuffer(positionUs);
castNonNull(mediaPeriod).reevaluateBuffer(positionUs);
}
@Override
@ -206,14 +213,14 @@ public final class DeferredMediaPeriod implements MediaPeriod, MediaPeriod.Callb
@Override
public void onContinueLoadingRequested(MediaPeriod source) {
callback.onContinueLoadingRequested(this);
castNonNull(callback).onContinueLoadingRequested(this);
}
// MediaPeriod.Callback implementation
@Override
public void onPrepared(MediaPeriod mediaPeriod) {
callback.onPrepared(this);
castNonNull(callback).onPrepared(this);
}
private long getPreparePositionWithOverride(long preparePositionUs) {

View File

@ -242,8 +242,8 @@ public final class ExtractorMediaSource extends BaseMediaSource
Uri uri,
DataSource.Factory dataSourceFactory,
ExtractorsFactory extractorsFactory,
Handler eventHandler,
EventListener eventListener) {
@Nullable Handler eventHandler,
@Nullable EventListener eventListener) {
this(uri, dataSourceFactory, extractorsFactory, eventHandler, eventListener, null);
}
@ -264,9 +264,9 @@ public final class ExtractorMediaSource extends BaseMediaSource
Uri uri,
DataSource.Factory dataSourceFactory,
ExtractorsFactory extractorsFactory,
Handler eventHandler,
EventListener eventListener,
String customCacheKey) {
@Nullable Handler eventHandler,
@Nullable EventListener eventListener,
@Nullable String customCacheKey) {
this(
uri,
dataSourceFactory,
@ -296,9 +296,9 @@ public final class ExtractorMediaSource extends BaseMediaSource
Uri uri,
DataSource.Factory dataSourceFactory,
ExtractorsFactory extractorsFactory,
Handler eventHandler,
EventListener eventListener,
String customCacheKey,
@Nullable Handler eventHandler,
@Nullable EventListener eventListener,
@Nullable String customCacheKey,
int continueLoadingCheckIntervalBytes) {
this(
uri,

View File

@ -15,6 +15,7 @@
*/
package com.google.android.exoplayer2.source;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.SeekParameters;
import com.google.android.exoplayer2.trackselection.TrackSelection;
@ -23,6 +24,7 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.IdentityHashMap;
import org.checkerframework.checker.nullness.compatqual.NullableType;
/**
* Merges multiple {@link MediaPeriod}s.
@ -35,9 +37,8 @@ import java.util.IdentityHashMap;
private final CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
private final ArrayList<MediaPeriod> childrenPendingPreparation;
private Callback callback;
private TrackGroupArray trackGroups;
@Nullable private Callback callback;
@Nullable private TrackGroupArray trackGroups;
private MediaPeriod[] enabledPeriods;
private SequenceableLoader compositeSequenceableLoader;
@ -49,6 +50,7 @@ import java.util.IdentityHashMap;
compositeSequenceableLoader =
compositeSequenceableLoaderFactory.createCompositeSequenceableLoader();
streamPeriodIndices = new IdentityHashMap<>();
enabledPeriods = new MediaPeriod[0];
}
@Override
@ -69,12 +71,16 @@ import java.util.IdentityHashMap;
@Override
public TrackGroupArray getTrackGroups() {
return trackGroups;
return Assertions.checkNotNull(trackGroups);
}
@Override
public long selectTracks(TrackSelection[] selections, boolean[] mayRetainStreamFlags,
SampleStream[] streams, boolean[] streamResetFlags, long positionUs) {
public long selectTracks(
@NullableType TrackSelection[] selections,
boolean[] mayRetainStreamFlags,
@NullableType SampleStream[] streams,
boolean[] streamResetFlags,
long positionUs) {
// Map each selection and stream onto a child period index.
int[] streamChildIndices = new int[selections.length];
int[] selectionChildIndices = new int[selections.length];
@ -94,9 +100,9 @@ import java.util.IdentityHashMap;
}
streamPeriodIndices.clear();
// Select tracks for each child, copying the resulting streams back into a new streams array.
SampleStream[] newStreams = new SampleStream[selections.length];
SampleStream[] childStreams = new SampleStream[selections.length];
TrackSelection[] childSelections = new TrackSelection[selections.length];
@NullableType SampleStream[] newStreams = new SampleStream[selections.length];
@NullableType SampleStream[] childStreams = new SampleStream[selections.length];
@NullableType TrackSelection[] childSelections = new TrackSelection[selections.length];
ArrayList<MediaPeriod> enabledPeriodsList = new ArrayList<>(periods.length);
for (int i = 0; i < periods.length; i++) {
for (int j = 0; j < selections.length; j++) {
@ -114,10 +120,10 @@ import java.util.IdentityHashMap;
for (int j = 0; j < selections.length; j++) {
if (selectionChildIndices[j] == i) {
// Assert that the child provided a stream for the selection.
Assertions.checkState(childStreams[j] != null);
SampleStream childStream = Assertions.checkNotNull(childStreams[j]);
newStreams[j] = childStreams[j];
periodEnabled = true;
streamPeriodIndices.put(childStreams[j], i);
streamPeriodIndices.put(childStream, i);
} else if (streamChildIndices[j] == i) {
// Assert that the child cleared any previous stream.
Assertions.checkState(childStreams[j] == null);
@ -208,7 +214,8 @@ import java.util.IdentityHashMap;
@Override
public long getAdjustedSeekPositionUs(long positionUs, SeekParameters seekParameters) {
return enabledPeriods[0].getAdjustedSeekPositionUs(positionUs, seekParameters);
MediaPeriod queryPeriod = enabledPeriods.length > 0 ? enabledPeriods[0] : periods[0];
return queryPeriod.getAdjustedSeekPositionUs(positionUs, seekParameters);
}
// MediaPeriod.Callback implementation
@ -233,12 +240,12 @@ import java.util.IdentityHashMap;
}
}
trackGroups = new TrackGroupArray(trackGroupArray);
callback.onPrepared(this);
Assertions.checkNotNull(callback).onPrepared(this);
}
@Override
public void onContinueLoadingRequested(MediaPeriod ignored) {
callback.onContinueLoadingRequested(this);
Assertions.checkNotNull(callback).onContinueLoadingRequested(this);
}
}

View File

@ -71,9 +71,9 @@ public final class MergingMediaSource extends CompositeMediaSource<Integer> {
private final ArrayList<MediaSource> pendingTimelineSources;
private final CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
private Object primaryManifest;
@Nullable private Object primaryManifest;
private int periodCount;
private IllegalMergeException mergeError;
@Nullable private IllegalMergeException mergeError;
/**
* @param mediaSources The {@link MediaSource}s to merge.
@ -170,11 +170,13 @@ public final class MergingMediaSource extends CompositeMediaSource<Integer> {
}
@Override
protected @Nullable MediaPeriodId getMediaPeriodIdForChildMediaPeriodId(
@Nullable
protected MediaPeriodId getMediaPeriodIdForChildMediaPeriodId(
Integer id, MediaPeriodId mediaPeriodId) {
return id == 0 ? mediaPeriodId : null;
}
@Nullable
private IllegalMergeException checkTimelineMerges(Timeline timeline) {
if (periodCount == PERIOD_COUNT_UNSET) {
periodCount = timeline.getPeriodCount();

View File

@ -31,11 +31,14 @@ import com.google.android.exoplayer2.upstream.Loader.LoadErrorAction;
import com.google.android.exoplayer2.upstream.Loader.Loadable;
import com.google.android.exoplayer2.upstream.StatsDataSource;
import com.google.android.exoplayer2.upstream.TransferListener;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.MimeTypes;
import com.google.android.exoplayer2.util.Util;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import org.checkerframework.checker.nullness.compatqual.NullableType;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
/**
* A {@link MediaPeriod} with a single sample.
@ -64,8 +67,7 @@ import java.util.Arrays;
/* package */ boolean notifiedReadingStarted;
/* package */ boolean loadingFinished;
/* package */ boolean loadingSucceeded;
/* package */ byte[] sampleData;
/* package */ byte @MonotonicNonNull [] sampleData;
/* package */ int sampleSize;
public SingleSampleMediaPeriod(
@ -112,8 +114,12 @@ import java.util.Arrays;
}
@Override
public long selectTracks(TrackSelection[] selections, boolean[] mayRetainStreamFlags,
SampleStream[] streams, boolean[] streamResetFlags, long positionUs) {
public long selectTracks(
@NullableType TrackSelection[] selections,
boolean[] mayRetainStreamFlags,
@NullableType SampleStream[] streams,
boolean[] streamResetFlags,
long positionUs) {
for (int i = 0; i < selections.length; i++) {
if (streams[i] != null && (selections[i] == null || !mayRetainStreamFlags[i])) {
sampleStreams.remove(streams[i]);
@ -204,9 +210,8 @@ import java.util.Arrays;
public void onLoadCompleted(SourceLoadable loadable, long elapsedRealtimeMs,
long loadDurationMs) {
sampleSize = (int) loadable.dataSource.getBytesRead();
sampleData = loadable.sampleData;
sampleData = Assertions.checkNotNull(loadable.sampleData);
loadingFinished = true;
loadingSucceeded = true;
eventDispatcher.loadCompleted(
loadable.dataSpec,
loadable.dataSource.getLastOpenedUri(),
@ -325,7 +330,7 @@ import java.util.Arrays;
streamState = STREAM_STATE_SEND_SAMPLE;
return C.RESULT_FORMAT_READ;
} else if (loadingFinished) {
if (loadingSucceeded) {
if (sampleData != null) {
buffer.addFlag(C.BUFFER_FLAG_KEY_FRAME);
buffer.timeUs = 0;
if (buffer.isFlagsOnly()) {
@ -371,7 +376,7 @@ import java.util.Arrays;
private final StatsDataSource dataSource;
private byte[] sampleData;
@Nullable private byte[] sampleData;
public SourceLoadable(DataSpec dataSpec, DataSource dataSource) {
this.dataSpec = dataSpec;

View File

@ -18,12 +18,15 @@ package com.google.android.exoplayer2.source.ads;
import android.net.Uri;
import androidx.annotation.CheckResult;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Util;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
import org.checkerframework.checker.nullness.compatqual.NullableType;
/**
* Represents ad group times relative to the start of the media and information on the state and
@ -45,9 +48,9 @@ public final class AdPlaybackState {
/** The number of ads in the ad group, or {@link C#LENGTH_UNSET} if unknown. */
public final int count;
/** The URI of each ad in the ad group. */
public final Uri[] uris;
public final @NullableType Uri[] uris;
/** The state of each ad in the ad group. */
public final @AdState int[] states;
@AdState public final int[] states;
/** The durations of each ad in the ad group, in microseconds. */
public final long[] durationsUs;
@ -60,7 +63,8 @@ public final class AdPlaybackState {
/* durationsUs= */ new long[0]);
}
private AdGroup(int count, @AdState int[] states, Uri[] uris, long[] durationsUs) {
private AdGroup(
int count, @AdState int[] states, @NullableType Uri[] uris, long[] durationsUs) {
Assertions.checkArgument(states.length == uris.length);
this.count = count;
this.states = states;
@ -98,7 +102,7 @@ public final class AdPlaybackState {
}
@Override
public boolean equals(Object o) {
public boolean equals(@Nullable Object o) {
if (this == o) {
return true;
}
@ -130,7 +134,7 @@ public final class AdPlaybackState {
Assertions.checkArgument(this.count == C.LENGTH_UNSET && states.length <= count);
@AdState int[] states = copyStatesWithSpaceForAdCount(this.states, count);
long[] durationsUs = copyDurationsUsWithSpaceForAdCount(this.durationsUs, count);
Uri[] uris = Arrays.copyOf(this.uris, count);
@NullableType Uri[] uris = Arrays.copyOf(this.uris, count);
return new AdGroup(count, states, uris, durationsUs);
}
@ -151,7 +155,7 @@ public final class AdPlaybackState {
this.durationsUs.length == states.length
? this.durationsUs
: copyDurationsUsWithSpaceForAdCount(this.durationsUs, states.length);
Uri[] uris = Arrays.copyOf(this.uris, states.length);
@NullableType Uri[] uris = Arrays.copyOf(this.uris, states.length);
uris[index] = uri;
states[index] = AD_STATE_AVAILABLE;
return new AdGroup(count, states, uris, durationsUs);
@ -177,6 +181,7 @@ public final class AdPlaybackState {
this.durationsUs.length == states.length
? this.durationsUs
: copyDurationsUsWithSpaceForAdCount(this.durationsUs, states.length);
@NullableType
Uri[] uris =
this.uris.length == states.length ? this.uris : Arrays.copyOf(this.uris, states.length);
states[index] = state;
@ -362,7 +367,7 @@ public final class AdPlaybackState {
if (adGroups[adGroupIndex].count == adCount) {
return this;
}
AdGroup[] adGroups = Arrays.copyOf(this.adGroups, this.adGroups.length);
AdGroup[] adGroups = Util.nullSafeArrayCopy(this.adGroups, this.adGroups.length);
adGroups[adGroupIndex] = this.adGroups[adGroupIndex].withAdCount(adCount);
return new AdPlaybackState(adGroupTimesUs, adGroups, adResumePositionUs, contentDurationUs);
}
@ -370,7 +375,7 @@ public final class AdPlaybackState {
/** Returns an instance with the specified ad URI. */
@CheckResult
public AdPlaybackState withAdUri(int adGroupIndex, int adIndexInAdGroup, Uri uri) {
AdGroup[] adGroups = Arrays.copyOf(this.adGroups, this.adGroups.length);
AdGroup[] adGroups = Util.nullSafeArrayCopy(this.adGroups, this.adGroups.length);
adGroups[adGroupIndex] = adGroups[adGroupIndex].withAdUri(uri, adIndexInAdGroup);
return new AdPlaybackState(adGroupTimesUs, adGroups, adResumePositionUs, contentDurationUs);
}
@ -378,7 +383,7 @@ public final class AdPlaybackState {
/** Returns an instance with the specified ad marked as played. */
@CheckResult
public AdPlaybackState withPlayedAd(int adGroupIndex, int adIndexInAdGroup) {
AdGroup[] adGroups = Arrays.copyOf(this.adGroups, this.adGroups.length);
AdGroup[] adGroups = Util.nullSafeArrayCopy(this.adGroups, this.adGroups.length);
adGroups[adGroupIndex] = adGroups[adGroupIndex].withAdState(AD_STATE_PLAYED, adIndexInAdGroup);
return new AdPlaybackState(adGroupTimesUs, adGroups, adResumePositionUs, contentDurationUs);
}
@ -386,7 +391,7 @@ public final class AdPlaybackState {
/** Returns an instance with the specified ad marked as skipped. */
@CheckResult
public AdPlaybackState withSkippedAd(int adGroupIndex, int adIndexInAdGroup) {
AdGroup[] adGroups = Arrays.copyOf(this.adGroups, this.adGroups.length);
AdGroup[] adGroups = Util.nullSafeArrayCopy(this.adGroups, this.adGroups.length);
adGroups[adGroupIndex] = adGroups[adGroupIndex].withAdState(AD_STATE_SKIPPED, adIndexInAdGroup);
return new AdPlaybackState(adGroupTimesUs, adGroups, adResumePositionUs, contentDurationUs);
}
@ -394,7 +399,7 @@ public final class AdPlaybackState {
/** Returns an instance with the specified ad marked as having a load error. */
@CheckResult
public AdPlaybackState withAdLoadError(int adGroupIndex, int adIndexInAdGroup) {
AdGroup[] adGroups = Arrays.copyOf(this.adGroups, this.adGroups.length);
AdGroup[] adGroups = Util.nullSafeArrayCopy(this.adGroups, this.adGroups.length);
adGroups[adGroupIndex] = adGroups[adGroupIndex].withAdState(AD_STATE_ERROR, adIndexInAdGroup);
return new AdPlaybackState(adGroupTimesUs, adGroups, adResumePositionUs, contentDurationUs);
}
@ -405,7 +410,7 @@ public final class AdPlaybackState {
*/
@CheckResult
public AdPlaybackState withSkippedAdGroup(int adGroupIndex) {
AdGroup[] adGroups = Arrays.copyOf(this.adGroups, this.adGroups.length);
AdGroup[] adGroups = Util.nullSafeArrayCopy(this.adGroups, this.adGroups.length);
adGroups[adGroupIndex] = adGroups[adGroupIndex].withAllAdsSkipped();
return new AdPlaybackState(adGroupTimesUs, adGroups, adResumePositionUs, contentDurationUs);
}
@ -413,7 +418,7 @@ public final class AdPlaybackState {
/** Returns an instance with the specified ad durations, in microseconds. */
@CheckResult
public AdPlaybackState withAdDurationsUs(long[][] adDurationUs) {
AdGroup[] adGroups = Arrays.copyOf(this.adGroups, this.adGroups.length);
AdGroup[] adGroups = Util.nullSafeArrayCopy(this.adGroups, this.adGroups.length);
for (int adGroupIndex = 0; adGroupIndex < adGroupCount; adGroupIndex++) {
adGroups[adGroupIndex] = adGroups[adGroupIndex].withAdDurationsUs(adDurationUs[adGroupIndex]);
}
@ -441,7 +446,7 @@ public final class AdPlaybackState {
}
@Override
public boolean equals(Object o) {
public boolean equals(@Nullable Object o) {
if (this == o) {
return true;
}

View File

@ -47,6 +47,7 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.checkerframework.checker.nullness.compatqual.NullableType;
/**
* A {@link MediaSource} that inserts ads linearly with a provided content media source. This source
@ -114,7 +115,7 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
*/
public RuntimeException getRuntimeExceptionForUnexpected() {
Assertions.checkState(type == TYPE_UNEXPECTED);
return (RuntimeException) getCause();
return (RuntimeException) Assertions.checkNotNull(getCause());
}
}
@ -131,12 +132,12 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
private final Timeline.Period period;
// Accessed on the player thread.
private ComponentListener componentListener;
private Timeline contentTimeline;
private Object contentManifest;
private AdPlaybackState adPlaybackState;
private MediaSource[][] adGroupMediaSources;
private Timeline[][] adGroupTimelines;
@Nullable private ComponentListener componentListener;
@Nullable private Timeline contentTimeline;
@Nullable private Object contentManifest;
@Nullable private AdPlaybackState adPlaybackState;
private @NullableType MediaSource[][] adGroupMediaSources;
private @NullableType Timeline[][] adGroupTimelines;
/**
* Constructs a new source that inserts ads linearly with the content specified by {@code
@ -202,24 +203,25 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
@Override
public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator, long startPositionUs) {
AdPlaybackState adPlaybackState = Assertions.checkNotNull(this.adPlaybackState);
if (adPlaybackState.adGroupCount > 0 && id.isAd()) {
int adGroupIndex = id.adGroupIndex;
int adIndexInAdGroup = id.adIndexInAdGroup;
Uri adUri = adPlaybackState.adGroups[adGroupIndex].uris[adIndexInAdGroup];
Uri adUri =
Assertions.checkNotNull(adPlaybackState.adGroups[adGroupIndex].uris[adIndexInAdGroup]);
if (adGroupMediaSources[adGroupIndex].length <= adIndexInAdGroup) {
MediaSource adMediaSource = adMediaSourceFactory.createMediaSource(adUri);
int oldAdCount = adGroupMediaSources[adGroupIndex].length;
if (adIndexInAdGroup >= oldAdCount) {
int adCount = adIndexInAdGroup + 1;
adGroupMediaSources[adGroupIndex] =
Arrays.copyOf(adGroupMediaSources[adGroupIndex], adCount);
adGroupTimelines[adGroupIndex] = Arrays.copyOf(adGroupTimelines[adGroupIndex], adCount);
}
adGroupMediaSources[adGroupIndex][adIndexInAdGroup] = adMediaSource;
deferredMediaPeriodByAdMediaSource.put(adMediaSource, new ArrayList<>());
prepareChildSource(id, adMediaSource);
}
MediaSource mediaSource = adGroupMediaSources[adGroupIndex][adIndexInAdGroup];
if (mediaSource == null) {
mediaSource = adMediaSourceFactory.createMediaSource(adUri);
adGroupMediaSources[adGroupIndex][adIndexInAdGroup] = mediaSource;
deferredMediaPeriodByAdMediaSource.put(mediaSource, new ArrayList<>());
prepareChildSource(id, mediaSource);
}
DeferredMediaPeriod deferredMediaPeriod =
new DeferredMediaPeriod(mediaSource, id, allocator, startPositionUs);
deferredMediaPeriod.setPrepareErrorListener(
@ -227,7 +229,8 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
List<DeferredMediaPeriod> mediaPeriods = deferredMediaPeriodByAdMediaSource.get(mediaSource);
if (mediaPeriods == null) {
Object periodUid =
adGroupTimelines[adGroupIndex][adIndexInAdGroup].getUidOfPeriod(/* periodIndex= */ 0);
Assertions.checkNotNull(adGroupTimelines[adGroupIndex][adIndexInAdGroup])
.getUidOfPeriod(/* periodIndex= */ 0);
MediaPeriodId adSourceMediaPeriodId = new MediaPeriodId(periodUid, id.windowSequenceNumber);
deferredMediaPeriod.createPeriod(adSourceMediaPeriodId);
} else {
@ -258,7 +261,7 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
@Override
public void releaseSourceInternal() {
super.releaseSourceInternal();
componentListener.release();
Assertions.checkNotNull(componentListener).release();
componentListener = null;
deferredMediaPeriodByAdMediaSource.clear();
contentTimeline = null;
@ -305,7 +308,7 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
maybeUpdateSourceInfo();
}
private void onContentSourceInfoRefreshed(Timeline timeline, Object manifest) {
private void onContentSourceInfoRefreshed(Timeline timeline, @Nullable Object manifest) {
Assertions.checkArgument(timeline.getPeriodCount() == 1);
contentTimeline = timeline;
contentManifest = manifest;
@ -330,6 +333,7 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
}
private void maybeUpdateSourceInfo() {
Timeline contentTimeline = this.contentTimeline;
if (adPlaybackState != null && contentTimeline != null) {
adPlaybackState = adPlaybackState.withAdDurationsUs(getAdDurations(adGroupTimelines, period));
Timeline timeline =
@ -340,7 +344,8 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
}
}
private static long[][] getAdDurations(Timeline[][] adTimelines, Timeline.Period period) {
private static long[][] getAdDurations(
@NullableType Timeline[][] adTimelines, Timeline.Period period) {
long[][] adDurations = new long[adTimelines.length][];
for (int i = 0; i < adTimelines.length; i++) {
adDurations[i] = new long[adTimelines[i].length];