diff --git a/library/common/src/main/java/com/google/android/exoplayer2/source/MediaPeriodId.java b/library/common/src/main/java/com/google/android/exoplayer2/source/MediaPeriodId.java new file mode 100644 index 0000000000..ad0e289ba9 --- /dev/null +++ b/library/common/src/main/java/com/google/android/exoplayer2/source/MediaPeriodId.java @@ -0,0 +1,187 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2.source; + +import androidx.annotation.Nullable; +import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.Timeline; + +/** + * Identifies a specific playback of a {@link Timeline.Period}. + * + *

A {@link Timeline.Period} can be played multiple times, for example if it is repeated. Each + * instances of this class identifies a specific playback of a {@link Timeline.Period}. + * + *

In ExoPlayer's implementation, {@link MediaPeriodId} identifies a {@code MediaPeriod}. + */ +// TODO(b/172315872) Should be final, but subclassed in MediaSource for backward-compatibility. +public class MediaPeriodId { + + /** The unique id of the timeline period. */ + public final Object periodUid; + + /** + * If the media period is in an ad group, the index of the ad group in the period. {@link + * C#INDEX_UNSET} otherwise. + */ + public final int adGroupIndex; + + /** + * If the media period is in an ad group, the index of the ad in its ad group in the period. + * {@link C#INDEX_UNSET} otherwise. + */ + public final int adIndexInAdGroup; + + /** + * The sequence number of the window in the buffered sequence of windows this media period is part + * of. {@link C#INDEX_UNSET} if the media period id is not part of a buffered sequence of windows. + */ + public final long windowSequenceNumber; + + /** + * The index of the next ad group to which the media period's content is clipped, or {@link + * C#INDEX_UNSET} if there is no following ad group or if this media period is an ad. + */ + public final int nextAdGroupIndex; + + /** + * Creates a media period identifier for a period which is not part of a buffered sequence of + * windows. + * + * @param periodUid The unique id of the timeline period. + */ + public MediaPeriodId(Object periodUid) { + this(periodUid, /* windowSequenceNumber= */ C.INDEX_UNSET); + } + + /** + * Creates a media period identifier for the specified period in the timeline. + * + * @param periodUid The unique id of the timeline period. + * @param windowSequenceNumber The sequence number of the window in the buffered sequence of + * windows this media period is part of. + */ + public MediaPeriodId(Object periodUid, long windowSequenceNumber) { + this( + periodUid, + /* adGroupIndex= */ C.INDEX_UNSET, + /* adIndexInAdGroup= */ C.INDEX_UNSET, + windowSequenceNumber, + /* nextAdGroupIndex= */ C.INDEX_UNSET); + } + + /** + * Creates a media period identifier for the specified clipped period in the timeline. + * + * @param periodUid The unique id of the timeline period. + * @param windowSequenceNumber The sequence number of the window in the buffered sequence of + * windows this media period is part of. + * @param nextAdGroupIndex The index of the next ad group to which the media period's content is + * clipped. + */ + public MediaPeriodId(Object periodUid, long windowSequenceNumber, int nextAdGroupIndex) { + this( + periodUid, + /* adGroupIndex= */ C.INDEX_UNSET, + /* adIndexInAdGroup= */ C.INDEX_UNSET, + windowSequenceNumber, + nextAdGroupIndex); + } + + /** + * Creates a media period identifier that identifies an ad within an ad group at the specified + * timeline period. + * + * @param periodUid The unique id of the timeline period that contains the ad group. + * @param adGroupIndex The index of the ad group. + * @param adIndexInAdGroup The index of the ad in the ad group. + * @param windowSequenceNumber The sequence number of the window in the buffered sequence of + * windows this media period is part of. + */ + public MediaPeriodId( + Object periodUid, int adGroupIndex, int adIndexInAdGroup, long windowSequenceNumber) { + this( + periodUid, + adGroupIndex, + adIndexInAdGroup, + windowSequenceNumber, + /* nextAdGroupIndex= */ C.INDEX_UNSET); + } + + /** Copy constructor for inheritance. */ + // TODO(b/172315872) Delete when client have migrated from MediaSource.MediaPeriodId + protected MediaPeriodId(MediaPeriodId mediaPeriodId) { + this.periodUid = mediaPeriodId.periodUid; + this.adGroupIndex = mediaPeriodId.adGroupIndex; + this.adIndexInAdGroup = mediaPeriodId.adIndexInAdGroup; + this.windowSequenceNumber = mediaPeriodId.windowSequenceNumber; + this.nextAdGroupIndex = mediaPeriodId.nextAdGroupIndex; + } + + private MediaPeriodId( + Object periodUid, + int adGroupIndex, + int adIndexInAdGroup, + long windowSequenceNumber, + int nextAdGroupIndex) { + this.periodUid = periodUid; + this.adGroupIndex = adGroupIndex; + this.adIndexInAdGroup = adIndexInAdGroup; + this.windowSequenceNumber = windowSequenceNumber; + this.nextAdGroupIndex = nextAdGroupIndex; + } + + /** Returns a copy of this period identifier but with {@code newPeriodUid} as its period uid. */ + public MediaPeriodId copyWithPeriodUid(Object newPeriodUid) { + return periodUid.equals(newPeriodUid) + ? this + : new MediaPeriodId( + newPeriodUid, adGroupIndex, adIndexInAdGroup, windowSequenceNumber, nextAdGroupIndex); + } + + /** Returns whether this period identifier identifies an ad in an ad group in a period. */ + public boolean isAd() { + return adGroupIndex != C.INDEX_UNSET; + } + + @Override + public boolean equals(@Nullable Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof MediaPeriodId)) { + return false; + } + + MediaPeriodId periodId = (MediaPeriodId) obj; + return periodUid.equals(periodId.periodUid) + && adGroupIndex == periodId.adGroupIndex + && adIndexInAdGroup == periodId.adIndexInAdGroup + && windowSequenceNumber == periodId.windowSequenceNumber + && nextAdGroupIndex == periodId.nextAdGroupIndex; + } + + @Override + public int hashCode() { + int result = 17; + result = 31 * result + periodUid.hashCode(); + result = 31 * result + adGroupIndex; + result = 31 * result + adIndexInAdGroup; + result = 31 * result + (int) windowSequenceNumber; + result = 31 * result + nextAdGroupIndex; + return result; + } +} diff --git a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlaybackException.java b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlaybackException.java index 6653cf572c..7e8f613e73 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/ExoPlaybackException.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/ExoPlaybackException.java @@ -21,6 +21,7 @@ import androidx.annotation.CheckResult; import androidx.annotation.IntDef; import androidx.annotation.Nullable; import com.google.android.exoplayer2.C.FormatSupport; +import com.google.android.exoplayer2.source.MediaPeriodId; import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.util.Assertions; import java.io.IOException; @@ -133,11 +134,8 @@ public final class ExoPlaybackException extends Exception { /** The value of {@link SystemClock#elapsedRealtime()} when this exception was created. */ public final long timestampMs; - /** - * The {@link MediaSource.MediaPeriodId} of the media associated with this error, or null if - * undetermined. - */ - @Nullable public final MediaSource.MediaPeriodId mediaPeriodId; + /** The {@link MediaPeriodId} of the media associated with this error, or null if undetermined. */ + @Nullable public final MediaPeriodId mediaPeriodId; /** * Whether the error may be recoverable. @@ -334,7 +332,7 @@ public final class ExoPlaybackException extends Exception { int rendererIndex, @Nullable Format rendererFormat, @FormatSupport int rendererFormatSupport, - @Nullable MediaSource.MediaPeriodId mediaPeriodId, + @Nullable MediaPeriodId mediaPeriodId, @TimeoutOperation int timeoutOperation, long timestampMs, boolean isRecoverable) { @@ -402,14 +400,13 @@ public final class ExoPlaybackException extends Exception { } /** - * Returns a copy of this exception with the provided {@link MediaSource.MediaPeriodId}. + * Returns a copy of this exception with the provided {@link MediaPeriodId}. * - * @param mediaPeriodId The {@link MediaSource.MediaPeriodId}. + * @param mediaPeriodId The {@link MediaPeriodId}. * @return The copied exception. */ @CheckResult - /* package */ ExoPlaybackException copyWithMediaPeriodId( - @Nullable MediaSource.MediaPeriodId mediaPeriodId) { + /* package */ ExoPlaybackException copyWithMediaPeriodId(@Nullable MediaPeriodId mediaPeriodId) { return new ExoPlaybackException( getMessage(), cause, diff --git a/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsCollector.java b/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsCollector.java index e7be6c342c..e8ab433d55 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsCollector.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/analytics/AnalyticsCollector.java @@ -646,7 +646,7 @@ public class AnalyticsCollector public final void onPlayerError(ExoPlaybackException error) { EventTime eventTime = error.mediaPeriodId != null - ? generateEventTime(error.mediaPeriodId) + ? generateEventTime(new MediaPeriodId(error.mediaPeriodId)) : generateCurrentPlayerMediaPeriodEventTime(); sendEvent( eventTime, diff --git a/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSource.java b/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSource.java index 94a9f82030..f6f2ab496d 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSource.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/source/MediaSource.java @@ -17,7 +17,6 @@ package com.google.android.exoplayer2.source; import android.os.Handler; import androidx.annotation.Nullable; -import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.MediaItem; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.drm.DrmSessionEventListener; @@ -61,155 +60,52 @@ public interface MediaSource { void onSourceInfoRefreshed(MediaSource source, Timeline timeline); } - /** Identifier for a {@link MediaPeriod}. */ - final class MediaPeriodId { + // TODO(b/172315872) Delete when all clients have been migrated to base class. + /** + * Identifier for a {@link MediaPeriod}. + * + *

Extends for backward-compatibility {@link + * com.google.android.exoplayer2.source.MediaPeriodId}. + */ + final class MediaPeriodId extends com.google.android.exoplayer2.source.MediaPeriodId { - /** The unique id of the timeline period. */ - public final Object periodUid; - - /** - * If the media period is in an ad group, the index of the ad group in the period. - * {@link C#INDEX_UNSET} otherwise. - */ - public final int adGroupIndex; - - /** - * If the media period is in an ad group, the index of the ad in its ad group in the period. - * {@link C#INDEX_UNSET} otherwise. - */ - public final int adIndexInAdGroup; - - /** - * The sequence number of the window in the buffered sequence of windows this media period is - * part of. {@link C#INDEX_UNSET} if the media period id is not part of a buffered sequence of - * windows. - */ - public final long windowSequenceNumber; - - /** - * The index of the next ad group to which the media period's content is clipped, or {@link - * C#INDEX_UNSET} if there is no following ad group or if this media period is an ad. - */ - public final int nextAdGroupIndex; - - /** - * Creates a media period identifier for a period which is not part of a buffered sequence of - * windows. - * - * @param periodUid The unique id of the timeline period. - */ + /** See {@link com.google.android.exoplayer2.source.MediaPeriodId#MediaPeriodId(Object)}. */ public MediaPeriodId(Object periodUid) { - this(periodUid, /* windowSequenceNumber= */ C.INDEX_UNSET); + super(periodUid); } /** - * Creates a media period identifier for the specified period in the timeline. - * - * @param periodUid The unique id of the timeline period. - * @param windowSequenceNumber The sequence number of the window in the buffered sequence of - * windows this media period is part of. + * See {@link com.google.android.exoplayer2.source.MediaPeriodId#MediaPeriodId(Object, long)}. */ public MediaPeriodId(Object periodUid, long windowSequenceNumber) { - this( - periodUid, - /* adGroupIndex= */ C.INDEX_UNSET, - /* adIndexInAdGroup= */ C.INDEX_UNSET, - windowSequenceNumber, - /* nextAdGroupIndex= */ C.INDEX_UNSET); + super(periodUid, windowSequenceNumber); } /** - * Creates a media period identifier for the specified clipped period in the timeline. - * - * @param periodUid The unique id of the timeline period. - * @param windowSequenceNumber The sequence number of the window in the buffered sequence of - * windows this media period is part of. - * @param nextAdGroupIndex The index of the next ad group to which the media period's content is - * clipped. + * See {@link com.google.android.exoplayer2.source.MediaPeriodId#MediaPeriodId(Object, long, + * int)}. */ public MediaPeriodId(Object periodUid, long windowSequenceNumber, int nextAdGroupIndex) { - this( - periodUid, - /* adGroupIndex= */ C.INDEX_UNSET, - /* adIndexInAdGroup= */ C.INDEX_UNSET, - windowSequenceNumber, - nextAdGroupIndex); + super(periodUid, windowSequenceNumber, nextAdGroupIndex); } /** - * Creates a media period identifier that identifies an ad within an ad group at the specified - * timeline period. - * - * @param periodUid The unique id of the timeline period that contains the ad group. - * @param adGroupIndex The index of the ad group. - * @param adIndexInAdGroup The index of the ad in the ad group. - * @param windowSequenceNumber The sequence number of the window in the buffered sequence of - * windows this media period is part of. + * See {@link com.google.android.exoplayer2.source.MediaPeriodId#MediaPeriodId(Object, int, int, + * long)}. */ public MediaPeriodId( Object periodUid, int adGroupIndex, int adIndexInAdGroup, long windowSequenceNumber) { - this( - periodUid, - adGroupIndex, - adIndexInAdGroup, - windowSequenceNumber, - /* nextAdGroupIndex= */ C.INDEX_UNSET); + super(periodUid, adGroupIndex, adIndexInAdGroup, windowSequenceNumber); } - private MediaPeriodId( - Object periodUid, - int adGroupIndex, - int adIndexInAdGroup, - long windowSequenceNumber, - int nextAdGroupIndex) { - this.periodUid = periodUid; - this.adGroupIndex = adGroupIndex; - this.adIndexInAdGroup = adIndexInAdGroup; - this.windowSequenceNumber = windowSequenceNumber; - this.nextAdGroupIndex = nextAdGroupIndex; + /** Wraps an {@link com.google.android.exoplayer2.source.MediaPeriodId} into a MediaPeriodId. */ + public MediaPeriodId(com.google.android.exoplayer2.source.MediaPeriodId mediaPeriodId) { + super(mediaPeriodId); } - /** Returns a copy of this period identifier but with {@code newPeriodUid} as its period uid. */ + /** See {@link com.google.android.exoplayer2.source.MediaPeriodId#copyWithPeriodUid(Object)}. */ public MediaPeriodId copyWithPeriodUid(Object newPeriodUid) { - return periodUid.equals(newPeriodUid) - ? this - : new MediaPeriodId( - newPeriodUid, adGroupIndex, adIndexInAdGroup, windowSequenceNumber, nextAdGroupIndex); - } - - /** - * Returns whether this period identifier identifies an ad in an ad group in a period. - */ - public boolean isAd() { - return adGroupIndex != C.INDEX_UNSET; - } - - @Override - public boolean equals(@Nullable Object obj) { - if (this == obj) { - return true; - } - if (obj == null || getClass() != obj.getClass()) { - return false; - } - - MediaPeriodId periodId = (MediaPeriodId) obj; - return periodUid.equals(periodId.periodUid) - && adGroupIndex == periodId.adGroupIndex - && adIndexInAdGroup == periodId.adIndexInAdGroup - && windowSequenceNumber == periodId.windowSequenceNumber - && nextAdGroupIndex == periodId.nextAdGroupIndex; - } - - @Override - public int hashCode() { - int result = 17; - result = 31 * result + periodUid.hashCode(); - result = 31 * result + adGroupIndex; - result = 31 * result + adIndexInAdGroup; - result = 31 * result + (int) windowSequenceNumber; - result = 31 * result + nextAdGroupIndex; - return result; + return new MediaPeriodId(super.copyWithPeriodUid(newPeriodUid)); } }