From 3e990a3d24e28eeaefd57f7e5bfb5b3522f05adb Mon Sep 17 00:00:00 2001 From: tonihei Date: Thu, 23 May 2019 16:54:45 +0100 Subject: [PATCH] Fix nullness warning for MediaSource/MediaPeriod classes. PiperOrigin-RevId: 249652301 --- .../source/AbstractConcatenatedTimeline.java | 7 ++- .../source/ClippingMediaPeriod.java | 29 ++++++----- .../source/ClippingMediaSource.java | 9 ++-- .../source/DeferredMediaPeriod.java | 41 ++++++++------- .../source/ExtractorMediaSource.java | 16 +++--- .../exoplayer2/source/MergingMediaPeriod.java | 35 ++++++++----- .../exoplayer2/source/MergingMediaSource.java | 8 +-- .../source/SingleSampleMediaPeriod.java | 21 +++++--- .../source/ads/AdPlaybackState.java | 33 +++++++----- .../exoplayer2/source/ads/AdsMediaSource.java | 51 ++++++++++--------- 10 files changed, 146 insertions(+), 104 deletions(-) diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/AbstractConcatenatedTimeline.java b/library/core/src/main/java/com/google/android/exoplayer2/source/AbstractConcatenatedTimeline.java index 4a3505749a..db19764318 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/AbstractConcatenatedTimeline.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/AbstractConcatenatedTimeline.java @@ -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; } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaPeriod.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaPeriod.java index c078053110..d57dccd8fe 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaPeriod.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaPeriod.java @@ -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); } - } - } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaSource.java index ce6254e975..c3e700fff5 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ClippingMediaSource.java @@ -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 { private final ArrayList 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 { Assertions.checkState(mediaPeriods.remove(mediaPeriod)); mediaSource.releasePeriod(((ClippingMediaPeriod) mediaPeriod).mediaPeriod); if (mediaPeriods.isEmpty() && !allowDynamicClippingUpdates) { - refreshClippedTimeline(clippingTimeline.timeline); + refreshClippedTimeline(Assertions.checkNotNull(clippingTimeline).timeline); } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/DeferredMediaPeriod.java b/library/core/src/main/java/com/google/android/exoplayer2/source/DeferredMediaPeriod.java index abf02541c8..95a218bfe7 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/DeferredMediaPeriod.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/DeferredMediaPeriod.java @@ -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) { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaSource.java index 3951dc20a2..841f18bab4 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ExtractorMediaSource.java @@ -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, diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/MergingMediaPeriod.java b/library/core/src/main/java/com/google/android/exoplayer2/source/MergingMediaPeriod.java index a4fc8c6b00..cafc052f34 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/MergingMediaPeriod.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/MergingMediaPeriod.java @@ -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 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 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); } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/MergingMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/MergingMediaSource.java index 6b1a362b59..7188cada0f 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/MergingMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/MergingMediaSource.java @@ -71,9 +71,9 @@ public final class MergingMediaSource extends CompositeMediaSource { private final ArrayList 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 { } @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(); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaPeriod.java b/library/core/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaPeriod.java index e0c2a00df3..6063168e99 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaPeriod.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/SingleSampleMediaPeriod.java @@ -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; diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ads/AdPlaybackState.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ads/AdPlaybackState.java index be9dea91f1..0a1628b3f9 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ads/AdPlaybackState.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ads/AdPlaybackState.java @@ -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; } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/ads/AdsMediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/ads/AdsMediaSource.java index 8828e34304..78b0f6de11 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/ads/AdsMediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/ads/AdsMediaSource.java @@ -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 { */ 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 { 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 { @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); + int adCount = adIndexInAdGroup + 1; + adGroupMediaSources[adGroupIndex] = + Arrays.copyOf(adGroupMediaSources[adGroupIndex], adCount); + adGroupTimelines[adGroupIndex] = Arrays.copyOf(adGroupTimelines[adGroupIndex], adCount); } 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 { List 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 { @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 { 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 { } 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 { } } - 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];