From a95f0643b94fd248a8afd3b2c61ad12a9d22746c Mon Sep 17 00:00:00 2001 From: tonihei Date: Tue, 15 Oct 2019 14:44:26 +0100 Subject: [PATCH] Set isLive flag in CastTimeline based on MediaInfo. Issue:#2668 PiperOrigin-RevId: 274793644 --- .../exoplayer2/ext/cast/CastTimeline.java | 47 ++++++++++++------- .../ext/cast/CastTimelineTracker.java | 34 +++++++++----- 2 files changed, 52 insertions(+), 29 deletions(-) diff --git a/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastTimeline.java b/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastTimeline.java index 54ff7e6777..a3bdc5e415 100644 --- a/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastTimeline.java +++ b/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastTimeline.java @@ -39,9 +39,14 @@ import java.util.Arrays; * The default start position of the item in microseconds, or {@link C#TIME_UNSET} if unknown. */ public final long defaultPositionUs; + /** Whether the item is live content, or {@code false} if unknown. */ + public final boolean isLive; private ItemData() { - this(/* durationUs= */ C.TIME_UNSET, /* defaultPositionUs */ C.TIME_UNSET); + this( + /* durationUs= */ C.TIME_UNSET, /* defaultPositionUs */ + C.TIME_UNSET, + /* isLive= */ false); } /** @@ -49,26 +54,29 @@ import java.util.Arrays; * * @param durationUs See {@link #durationsUs}. * @param defaultPositionUs See {@link #defaultPositionUs}. + * @param isLive See {@link #isLive}. */ - public ItemData(long durationUs, long defaultPositionUs) { + public ItemData(long durationUs, long defaultPositionUs, boolean isLive) { this.durationUs = durationUs; this.defaultPositionUs = defaultPositionUs; + this.isLive = isLive; } - /** Returns an instance with the given {@link #durationsUs}. */ - public ItemData copyWithDurationUs(long durationUs) { - if (durationUs == this.durationUs) { + /** + * Returns a copy of this instance with the given values. + * + * @param durationUs The duration in microseconds, or {@link C#TIME_UNSET} if unknown. + * @param defaultPositionUs The default start position in microseconds, or {@link C#TIME_UNSET} + * if unknown. + * @param isLive Whether the item is live, or {@code false} if unknown. + */ + public ItemData copyWithNewValues(long durationUs, long defaultPositionUs, boolean isLive) { + if (durationUs == this.durationUs + && defaultPositionUs == this.defaultPositionUs + && isLive == this.isLive) { return this; } - return new ItemData(durationUs, defaultPositionUs); - } - - /** Returns an instance with the given {@link #defaultPositionsUs}. */ - public ItemData copyWithDefaultPositionUs(long defaultPositionUs) { - if (defaultPositionUs == this.defaultPositionUs) { - return this; - } - return new ItemData(durationUs, defaultPositionUs); + return new ItemData(durationUs, defaultPositionUs, isLive); } } @@ -80,6 +88,7 @@ import java.util.Arrays; private final int[] ids; private final long[] durationsUs; private final long[] defaultPositionsUs; + private final boolean[] isLive; /** * Creates a Cast timeline from the given data. @@ -93,12 +102,14 @@ import java.util.Arrays; ids = Arrays.copyOf(itemIds, itemCount); durationsUs = new long[itemCount]; defaultPositionsUs = new long[itemCount]; + isLive = new boolean[itemCount]; for (int i = 0; i < ids.length; i++) { int id = ids[i]; idsToIndex.put(id, i); ItemData data = itemIdToData.get(id, ItemData.EMPTY); durationsUs[i] = data.durationUs; - defaultPositionsUs[i] = data.defaultPositionUs; + defaultPositionsUs[i] = data.defaultPositionUs == C.TIME_UNSET ? 0 : data.defaultPositionUs; + isLive[i] = data.isLive; } } @@ -121,7 +132,7 @@ import java.util.Arrays; /* windowStartTimeMs= */ C.TIME_UNSET, /* isSeekable= */ !isDynamic, isDynamic, - /* isLive= */ isDynamic, + isLive[windowIndex], defaultPositionsUs[windowIndex], durationUs, /* firstPeriodIndex= */ windowIndex, @@ -162,7 +173,8 @@ import java.util.Arrays; CastTimeline that = (CastTimeline) other; return Arrays.equals(ids, that.ids) && Arrays.equals(durationsUs, that.durationsUs) - && Arrays.equals(defaultPositionsUs, that.defaultPositionsUs); + && Arrays.equals(defaultPositionsUs, that.defaultPositionsUs) + && Arrays.equals(isLive, that.isLive); } @Override @@ -170,6 +182,7 @@ import java.util.Arrays; int result = Arrays.hashCode(ids); result = 31 * result + Arrays.hashCode(durationsUs); result = 31 * result + Arrays.hashCode(defaultPositionsUs); + result = 31 * result + Arrays.hashCode(isLive); return result; } diff --git a/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastTimelineTracker.java b/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastTimelineTracker.java index 40c93a115a..3ebd89c8fc 100644 --- a/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastTimelineTracker.java +++ b/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/CastTimelineTracker.java @@ -16,7 +16,9 @@ package com.google.android.exoplayer2.ext.cast; import android.util.SparseArray; +import androidx.annotation.Nullable; import com.google.android.exoplayer2.C; +import com.google.android.gms.cast.MediaInfo; import com.google.android.gms.cast.MediaQueueItem; import com.google.android.gms.cast.MediaStatus; import com.google.android.gms.cast.framework.media.RemoteMediaClient; @@ -61,25 +63,33 @@ import java.util.HashSet; } int currentItemId = mediaStatus.getCurrentItemId(); - long durationUs = CastUtils.getStreamDurationUs(mediaStatus.getMediaInfo()); - itemIdToData.put( - currentItemId, - itemIdToData - .get(currentItemId, CastTimeline.ItemData.EMPTY) - .copyWithDurationUs(durationUs)); + updateItemData( + currentItemId, mediaStatus.getMediaInfo(), /* defaultPositionUs= */ C.TIME_UNSET); for (MediaQueueItem item : mediaStatus.getQueueItems()) { - int itemId = item.getItemId(); - itemIdToData.put( - itemId, - itemIdToData - .get(itemId, CastTimeline.ItemData.EMPTY) - .copyWithDefaultPositionUs((long) (item.getStartTime() * C.MICROS_PER_SECOND))); + long defaultPositionUs = (long) (item.getStartTime() * C.MICROS_PER_SECOND); + updateItemData(item.getItemId(), item.getMedia(), defaultPositionUs); } return new CastTimeline(itemIds, itemIdToData); } + private void updateItemData(int itemId, @Nullable MediaInfo mediaInfo, long defaultPositionUs) { + CastTimeline.ItemData previousData = itemIdToData.get(itemId, CastTimeline.ItemData.EMPTY); + long durationUs = CastUtils.getStreamDurationUs(mediaInfo); + if (durationUs == C.TIME_UNSET) { + durationUs = previousData.durationUs; + } + boolean isLive = + mediaInfo == null + ? previousData.isLive + : mediaInfo.getStreamType() == MediaInfo.STREAM_TYPE_LIVE; + if (defaultPositionUs == C.TIME_UNSET) { + defaultPositionUs = previousData.defaultPositionUs; + } + itemIdToData.put(itemId, previousData.copyWithNewValues(durationUs, defaultPositionUs, isLive)); + } + private void removeUnusedItemDataEntries(int[] itemIds) { HashSet scratchItemIds = new HashSet<>(/* initialCapacity= */ itemIds.length * 2); for (int id : itemIds) {