mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Replace period index with uid in MediaPeriodId.
The MediaPeriodId with index is only properly defined together with a timeline containing the index. Changing it to the period uid allows to use the MediaPeriodId independent of the corresponding timeline. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=209430257
This commit is contained in:
parent
2cd7d7102b
commit
d51b98dd1f
@ -327,10 +327,10 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||
} else {
|
||||
long windowPositionUs = positionMs == C.TIME_UNSET
|
||||
? timeline.getWindow(windowIndex, window).getDefaultPositionUs() : C.msToUs(positionMs);
|
||||
Pair<Integer, Long> periodIndexAndPosition =
|
||||
Pair<Object, Long> periodUidAndPosition =
|
||||
timeline.getPeriodPosition(window, period, windowIndex, windowPositionUs);
|
||||
maskingWindowPositionMs = C.usToMs(windowPositionUs);
|
||||
maskingPeriodIndex = periodIndexAndPosition.first;
|
||||
maskingPeriodIndex = timeline.getIndexOfPeriod(periodUidAndPosition.first);
|
||||
}
|
||||
internalPlayer.seekTo(timeline, windowIndex, C.msToUs(positionMs));
|
||||
for (Player.EventListener listener : listeners) {
|
||||
@ -464,7 +464,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||
if (shouldMaskPosition()) {
|
||||
return maskingPeriodIndex;
|
||||
} else {
|
||||
return playbackInfo.periodId.periodIndex;
|
||||
return playbackInfo.timeline.getIndexOfPeriod(playbackInfo.periodId.periodUid);
|
||||
}
|
||||
}
|
||||
|
||||
@ -473,7 +473,8 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||
if (shouldMaskPosition()) {
|
||||
return maskingWindowIndex;
|
||||
} else {
|
||||
return playbackInfo.timeline.getPeriod(playbackInfo.periodId.periodIndex, period).windowIndex;
|
||||
return playbackInfo.timeline.getPeriodByUid(playbackInfo.periodId.periodUid, period)
|
||||
.windowIndex;
|
||||
}
|
||||
}
|
||||
|
||||
@ -499,7 +500,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||
}
|
||||
if (isPlayingAd()) {
|
||||
MediaPeriodId periodId = playbackInfo.periodId;
|
||||
timeline.getPeriod(periodId.periodIndex, period);
|
||||
timeline.getPeriodByUid(periodId.periodUid, period);
|
||||
long adDurationUs = period.getAdDurationUs(periodId.adGroupIndex, periodId.adIndexInAdGroup);
|
||||
return C.usToMs(adDurationUs);
|
||||
} else {
|
||||
@ -572,7 +573,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||
@Override
|
||||
public long getContentPosition() {
|
||||
if (isPlayingAd()) {
|
||||
playbackInfo.timeline.getPeriod(playbackInfo.periodId.periodIndex, period);
|
||||
playbackInfo.timeline.getPeriodByUid(playbackInfo.periodId.periodUid, period);
|
||||
return period.getPositionInWindowMs() + C.usToMs(playbackInfo.contentPositionUs);
|
||||
} else {
|
||||
return getCurrentPosition();
|
||||
@ -591,7 +592,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||
long contentBufferedPositionUs = playbackInfo.bufferedPositionUs;
|
||||
if (playbackInfo.loadingMediaPeriodId.isAd()) {
|
||||
Timeline.Period loadingPeriod =
|
||||
playbackInfo.timeline.getPeriod(playbackInfo.loadingMediaPeriodId.periodIndex, period);
|
||||
playbackInfo.timeline.getPeriodByUid(playbackInfo.loadingMediaPeriodId.periodUid, period);
|
||||
contentBufferedPositionUs =
|
||||
loadingPeriod.getAdGroupTimeUs(playbackInfo.loadingMediaPeriodId.adGroupIndex);
|
||||
if (contentBufferedPositionUs == C.TIME_END_OF_SOURCE) {
|
||||
@ -761,7 +762,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||
|
||||
private long periodPositionUsToWindowPositionMs(MediaPeriodId periodId, long positionUs) {
|
||||
long positionMs = C.usToMs(positionUs);
|
||||
playbackInfo.timeline.getPeriod(periodId.periodIndex, period);
|
||||
playbackInfo.timeline.getPeriodByUid(periodId.periodUid, period);
|
||||
positionMs += period.getPositionInWindowMs();
|
||||
return positionMs;
|
||||
}
|
||||
|
@ -594,7 +594,7 @@ import java.util.Collections;
|
||||
long periodPositionUs;
|
||||
long contentPositionUs;
|
||||
boolean seekPositionAdjusted;
|
||||
Pair<Integer, Long> resolvedSeekPosition =
|
||||
Pair<Object, Long> resolvedSeekPosition =
|
||||
resolveSeekPosition(seekPosition, /* trySubsequentPeriods= */ true);
|
||||
if (resolvedSeekPosition == null) {
|
||||
// The seek position was valid for the timeline that it was performed into, but the
|
||||
@ -605,9 +605,9 @@ import java.util.Collections;
|
||||
seekPositionAdjusted = true;
|
||||
} else {
|
||||
// Update the resolved seek position to take ads into account.
|
||||
int periodIndex = resolvedSeekPosition.first;
|
||||
Object periodUid = resolvedSeekPosition.first;
|
||||
contentPositionUs = resolvedSeekPosition.second;
|
||||
periodId = queue.resolveMediaPeriodIdForAds(periodIndex, contentPositionUs);
|
||||
periodId = queue.resolveMediaPeriodIdForAds(periodUid, contentPositionUs);
|
||||
if (periodId.isAd()) {
|
||||
periodPositionUs = 0;
|
||||
seekPositionAdjusted = true;
|
||||
@ -760,7 +760,7 @@ import java.util.Collections;
|
||||
int firstPeriodIndex =
|
||||
timeline.getWindow(timeline.getFirstWindowIndex(shuffleModeEnabled), window)
|
||||
.firstPeriodIndex;
|
||||
return new MediaPeriodId(firstPeriodIndex);
|
||||
return new MediaPeriodId(timeline.getUidOfPeriod(firstPeriodIndex));
|
||||
}
|
||||
|
||||
private void resetInternal(
|
||||
@ -889,7 +889,7 @@ import java.util.Collections;
|
||||
private boolean resolvePendingMessagePosition(PendingMessageInfo pendingMessageInfo) {
|
||||
if (pendingMessageInfo.resolvedPeriodUid == null) {
|
||||
// Position is still unresolved. Try to find window in current timeline.
|
||||
Pair<Integer, Long> periodPosition =
|
||||
Pair<Object, Long> periodPosition =
|
||||
resolveSeekPosition(
|
||||
new SeekPosition(
|
||||
pendingMessageInfo.message.getTimeline(),
|
||||
@ -900,9 +900,9 @@ import java.util.Collections;
|
||||
return false;
|
||||
}
|
||||
pendingMessageInfo.setResolvedPosition(
|
||||
periodPosition.first,
|
||||
playbackInfo.timeline.getIndexOfPeriod(periodPosition.first),
|
||||
periodPosition.second,
|
||||
playbackInfo.timeline.getUidOfPeriod(periodPosition.first));
|
||||
periodPosition.first);
|
||||
} else {
|
||||
// Position has been resolved for a previous timeline. Try to find the updated period index.
|
||||
int index = playbackInfo.timeline.getIndexOfPeriod(pendingMessageInfo.resolvedPeriodUid);
|
||||
@ -925,7 +925,8 @@ import java.util.Collections;
|
||||
oldPeriodPositionUs--;
|
||||
}
|
||||
// Correct next index if necessary (e.g. after seeking, timeline changes, or new messages)
|
||||
int currentPeriodIndex = playbackInfo.periodId.periodIndex;
|
||||
int currentPeriodIndex =
|
||||
playbackInfo.timeline.getIndexOfPeriod(playbackInfo.periodId.periodUid);
|
||||
PendingMessageInfo previousInfo =
|
||||
nextPendingMessageIndex > 0 ? pendingMessages.get(nextPendingMessageIndex - 1) : null;
|
||||
while (previousInfo != null
|
||||
@ -1153,7 +1154,7 @@ import java.util.Collections;
|
||||
playbackInfoUpdate.incrementPendingOperationAcks(pendingPrepareCount);
|
||||
pendingPrepareCount = 0;
|
||||
if (pendingInitialSeekPosition != null) {
|
||||
Pair<Integer, Long> periodPosition;
|
||||
Pair<Object, Long> periodPosition;
|
||||
try {
|
||||
periodPosition =
|
||||
resolveSeekPosition(pendingInitialSeekPosition, /* trySubsequentPeriods= */ true);
|
||||
@ -1168,9 +1169,9 @@ import java.util.Collections;
|
||||
// timeline has changed and a suitable seek position could not be resolved in the new one.
|
||||
handleSourceInfoRefreshEndedPlayback();
|
||||
} else {
|
||||
int periodIndex = periodPosition.first;
|
||||
Object periodUid = periodPosition.first;
|
||||
long positionUs = periodPosition.second;
|
||||
MediaPeriodId periodId = queue.resolveMediaPeriodIdForAds(periodIndex, positionUs);
|
||||
MediaPeriodId periodId = queue.resolveMediaPeriodIdForAds(periodUid, positionUs);
|
||||
playbackInfo =
|
||||
playbackInfo.fromNewPosition(
|
||||
periodId, periodId.isAd() ? 0 : positionUs, /* contentPositionUs= */ positionUs);
|
||||
@ -1179,11 +1180,12 @@ import java.util.Collections;
|
||||
if (timeline.isEmpty()) {
|
||||
handleSourceInfoRefreshEndedPlayback();
|
||||
} else {
|
||||
Pair<Integer, Long> defaultPosition = getPeriodPosition(timeline,
|
||||
timeline.getFirstWindowIndex(shuffleModeEnabled), C.TIME_UNSET);
|
||||
int periodIndex = defaultPosition.first;
|
||||
Pair<Object, Long> defaultPosition =
|
||||
getPeriodPosition(
|
||||
timeline, timeline.getFirstWindowIndex(shuffleModeEnabled), C.TIME_UNSET);
|
||||
Object periodUid = defaultPosition.first;
|
||||
long startPositionUs = defaultPosition.second;
|
||||
MediaPeriodId periodId = queue.resolveMediaPeriodIdForAds(periodIndex, startPositionUs);
|
||||
MediaPeriodId periodId = queue.resolveMediaPeriodIdForAds(periodUid, startPositionUs);
|
||||
playbackInfo =
|
||||
playbackInfo.fromNewPosition(
|
||||
periodId,
|
||||
@ -1197,12 +1199,12 @@ import java.util.Collections;
|
||||
if (oldTimeline.isEmpty()) {
|
||||
// If the old timeline is empty, the period queue is also empty.
|
||||
if (!timeline.isEmpty()) {
|
||||
Pair<Integer, Long> defaultPosition =
|
||||
Pair<Object, Long> defaultPosition =
|
||||
getPeriodPosition(
|
||||
timeline, timeline.getFirstWindowIndex(shuffleModeEnabled), C.TIME_UNSET);
|
||||
int periodIndex = defaultPosition.first;
|
||||
Object periodUid = defaultPosition.first;
|
||||
long startPositionUs = defaultPosition.second;
|
||||
MediaPeriodId periodId = queue.resolveMediaPeriodIdForAds(periodIndex, startPositionUs);
|
||||
MediaPeriodId periodId = queue.resolveMediaPeriodIdForAds(periodUid, startPositionUs);
|
||||
playbackInfo =
|
||||
playbackInfo.fromNewPosition(
|
||||
periodId,
|
||||
@ -1212,37 +1214,32 @@ import java.util.Collections;
|
||||
return;
|
||||
}
|
||||
MediaPeriodHolder periodHolder = queue.getFrontPeriod();
|
||||
int playingPeriodIndex = playbackInfo.periodId.periodIndex;
|
||||
long contentPositionUs = playbackInfo.contentPositionUs;
|
||||
Object playingPeriodUid =
|
||||
periodHolder == null ? oldTimeline.getUidOfPeriod(playingPeriodIndex) : periodHolder.uid;
|
||||
periodHolder == null ? playbackInfo.periodId.periodUid : periodHolder.uid;
|
||||
int periodIndex = timeline.getIndexOfPeriod(playingPeriodUid);
|
||||
if (periodIndex == C.INDEX_UNSET) {
|
||||
// We didn't find the current period in the new timeline. Attempt to resolve a subsequent
|
||||
// period whose window we can restart from.
|
||||
int newPeriodIndex = resolveSubsequentPeriod(playingPeriodIndex, oldTimeline, timeline);
|
||||
if (newPeriodIndex == C.INDEX_UNSET) {
|
||||
Object newPeriodUid = resolveSubsequentPeriod(playingPeriodUid, oldTimeline, timeline);
|
||||
if (newPeriodUid == null) {
|
||||
// We failed to resolve a suitable restart position.
|
||||
handleSourceInfoRefreshEndedPlayback();
|
||||
return;
|
||||
}
|
||||
// We resolved a subsequent period. Seek to the default position in the corresponding window.
|
||||
Pair<Integer, Long> defaultPosition = getPeriodPosition(timeline,
|
||||
timeline.getPeriod(newPeriodIndex, period).windowIndex, C.TIME_UNSET);
|
||||
newPeriodIndex = defaultPosition.first;
|
||||
Pair<Object, Long> defaultPosition =
|
||||
getPeriodPosition(
|
||||
timeline, timeline.getPeriodByUid(newPeriodUid, period).windowIndex, C.TIME_UNSET);
|
||||
newPeriodUid = defaultPosition.first;
|
||||
contentPositionUs = defaultPosition.second;
|
||||
MediaPeriodId periodId = queue.resolveMediaPeriodIdForAds(newPeriodIndex, contentPositionUs);
|
||||
MediaPeriodId periodId = queue.resolveMediaPeriodIdForAds(newPeriodUid, contentPositionUs);
|
||||
if (periodHolder != null) {
|
||||
// Clear the index of each holder that doesn't contain the default position. If a holder
|
||||
// contains the default position then update its index so it can be re-used when seeking.
|
||||
Object newPeriodUid = timeline.getUidOfPeriod(newPeriodIndex);
|
||||
periodHolder.info = periodHolder.info.copyWithPeriodIndex(C.INDEX_UNSET);
|
||||
// Update the new playing media period info if it already exists.
|
||||
while (periodHolder.next != null) {
|
||||
periodHolder = periodHolder.next;
|
||||
if (periodHolder.uid.equals(newPeriodUid)) {
|
||||
periodHolder.info = queue.getUpdatedMediaPeriodInfo(periodHolder.info, newPeriodIndex);
|
||||
} else {
|
||||
periodHolder.info = periodHolder.info.copyWithPeriodIndex(C.INDEX_UNSET);
|
||||
if (periodHolder.info.id.equals(periodId)) {
|
||||
periodHolder.info = queue.getUpdatedMediaPeriodInfo(periodHolder.info);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1252,14 +1249,10 @@ import java.util.Collections;
|
||||
return;
|
||||
}
|
||||
|
||||
// The current period is in the new timeline. Update the playback info.
|
||||
if (periodIndex != playingPeriodIndex) {
|
||||
playbackInfo = playbackInfo.copyWithPeriodIndex(periodIndex);
|
||||
}
|
||||
|
||||
MediaPeriodId playingPeriodId = playbackInfo.periodId;
|
||||
if (playingPeriodId.isAd()) {
|
||||
MediaPeriodId periodId = queue.resolveMediaPeriodIdForAds(periodIndex, contentPositionUs);
|
||||
MediaPeriodId periodId =
|
||||
queue.resolveMediaPeriodIdForAds(playingPeriodUid, contentPositionUs);
|
||||
if (!periodId.equals(playingPeriodId)) {
|
||||
// The previously playing ad should no longer be played, so skip it.
|
||||
long seekPositionUs =
|
||||
@ -1284,16 +1277,17 @@ import java.util.Collections;
|
||||
|
||||
/**
|
||||
* Given a period index into an old timeline, finds the first subsequent period that also exists
|
||||
* in a new timeline. The index of this period in the new timeline is returned.
|
||||
* in a new timeline. The uid of this period in the new timeline is returned.
|
||||
*
|
||||
* @param oldPeriodIndex The index of the period in the old timeline.
|
||||
* @param oldPeriodUid The index of the period in the old timeline.
|
||||
* @param oldTimeline The old timeline.
|
||||
* @param newTimeline The new timeline.
|
||||
* @return The index in the new timeline of the first subsequent period, or {@link C#INDEX_UNSET}
|
||||
* if no such period was found.
|
||||
* @return The uid in the new timeline of the first subsequent period, or null if no such period
|
||||
* was found.
|
||||
*/
|
||||
private int resolveSubsequentPeriod(
|
||||
int oldPeriodIndex, Timeline oldTimeline, Timeline newTimeline) {
|
||||
private @Nullable Object resolveSubsequentPeriod(
|
||||
Object oldPeriodUid, Timeline oldTimeline, Timeline newTimeline) {
|
||||
int oldPeriodIndex = oldTimeline.getIndexOfPeriod(oldPeriodUid);
|
||||
int newPeriodIndex = C.INDEX_UNSET;
|
||||
int maxIterations = oldTimeline.getPeriodCount();
|
||||
for (int i = 0; i < maxIterations && newPeriodIndex == C.INDEX_UNSET; i++) {
|
||||
@ -1305,11 +1299,11 @@ import java.util.Collections;
|
||||
}
|
||||
newPeriodIndex = newTimeline.getIndexOfPeriod(oldTimeline.getUidOfPeriod(oldPeriodIndex));
|
||||
}
|
||||
return newPeriodIndex;
|
||||
return newPeriodIndex == C.INDEX_UNSET ? null : newTimeline.getUidOfPeriod(newPeriodIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a {@link SeekPosition} into the corresponding (periodIndex, periodPositionUs) for the
|
||||
* Converts a {@link SeekPosition} into the corresponding (periodUid, periodPositionUs) for the
|
||||
* internal timeline.
|
||||
*
|
||||
* @param seekPosition The position to resolve.
|
||||
@ -1319,7 +1313,7 @@ import java.util.Collections;
|
||||
* @throws IllegalSeekPositionException If the window index of the seek position is outside the
|
||||
* bounds of the timeline.
|
||||
*/
|
||||
private Pair<Integer, Long> resolveSeekPosition(
|
||||
private Pair<Object, Long> resolveSeekPosition(
|
||||
SeekPosition seekPosition, boolean trySubsequentPeriods) {
|
||||
Timeline timeline = playbackInfo.timeline;
|
||||
Timeline seekTimeline = seekPosition.timeline;
|
||||
@ -1333,7 +1327,7 @@ import java.util.Collections;
|
||||
seekTimeline = timeline;
|
||||
}
|
||||
// Map the SeekPosition to a position in the corresponding timeline.
|
||||
Pair<Integer, Long> periodPosition;
|
||||
Pair<Object, Long> periodPosition;
|
||||
try {
|
||||
periodPosition = seekTimeline.getPeriodPosition(window, period, seekPosition.windowIndex,
|
||||
seekPosition.windowPositionUs);
|
||||
@ -1347,15 +1341,15 @@ import java.util.Collections;
|
||||
return periodPosition;
|
||||
}
|
||||
// Attempt to find the mapped period in the internal timeline.
|
||||
int periodIndex = timeline.getIndexOfPeriod(seekTimeline.getUidOfPeriod(periodPosition.first));
|
||||
int periodIndex = timeline.getIndexOfPeriod(periodPosition.first);
|
||||
if (periodIndex != C.INDEX_UNSET) {
|
||||
// We successfully located the period in the internal timeline.
|
||||
return Pair.create(periodIndex, periodPosition.second);
|
||||
return periodPosition;
|
||||
}
|
||||
if (trySubsequentPeriods) {
|
||||
// Try and find a subsequent period from the seek timeline in the internal timeline.
|
||||
periodIndex = resolveSubsequentPeriod(periodPosition.first, seekTimeline, timeline);
|
||||
if (periodIndex != C.INDEX_UNSET) {
|
||||
Object periodUid = resolveSubsequentPeriod(periodPosition.first, seekTimeline, timeline);
|
||||
if (periodUid != null) {
|
||||
// We found one. Map the SeekPosition onto the corresponding default position.
|
||||
return getPeriodPosition(
|
||||
timeline, timeline.getPeriod(periodIndex, period).windowIndex, C.TIME_UNSET);
|
||||
@ -1369,7 +1363,7 @@ import java.util.Collections;
|
||||
* Calls {@link Timeline#getPeriodPosition(Timeline.Window, Timeline.Period, int, long)} using the
|
||||
* current timeline.
|
||||
*/
|
||||
private Pair<Integer, Long> getPeriodPosition(
|
||||
private Pair<Object, Long> getPeriodPosition(
|
||||
Timeline timeline, int windowIndex, long windowPositionUs) {
|
||||
return timeline.getPeriodPosition(window, period, windowIndex, windowPositionUs);
|
||||
}
|
||||
@ -1506,14 +1500,12 @@ import java.util.Collections;
|
||||
if (info == null) {
|
||||
mediaSource.maybeThrowSourceInfoRefreshError();
|
||||
} else {
|
||||
Object uid = playbackInfo.timeline.getUidOfPeriod(info.id.periodIndex);
|
||||
MediaPeriod mediaPeriod =
|
||||
queue.enqueueNextMediaPeriod(
|
||||
rendererCapabilities,
|
||||
trackSelector,
|
||||
loadControl.getAllocator(),
|
||||
mediaSource,
|
||||
uid,
|
||||
info);
|
||||
mediaPeriod.prepare(this, info.startPositionUs);
|
||||
setIsLoading(true);
|
||||
|
@ -62,7 +62,6 @@ import com.google.android.exoplayer2.util.Assertions;
|
||||
* @param trackSelector The track selector.
|
||||
* @param allocator The allocator.
|
||||
* @param mediaSource The media source that produced the media period.
|
||||
* @param uid The unique identifier for the containing timeline period.
|
||||
* @param info Information used to identify this media period in its timeline period.
|
||||
*/
|
||||
public MediaPeriodHolder(
|
||||
@ -71,13 +70,12 @@ import com.google.android.exoplayer2.util.Assertions;
|
||||
TrackSelector trackSelector,
|
||||
Allocator allocator,
|
||||
MediaSource mediaSource,
|
||||
Object uid,
|
||||
MediaPeriodInfo info) {
|
||||
this.rendererCapabilities = rendererCapabilities;
|
||||
this.rendererPositionOffsetUs = rendererPositionOffsetUs - info.startPositionUs;
|
||||
this.trackSelector = trackSelector;
|
||||
this.mediaSource = mediaSource;
|
||||
this.uid = Assertions.checkNotNull(uid);
|
||||
this.uid = Assertions.checkNotNull(info.id.periodUid);
|
||||
this.info = info;
|
||||
sampleStreams = new SampleStream[rendererCapabilities.length];
|
||||
mayRetainStreamFlags = new boolean[rendererCapabilities.length];
|
||||
|
@ -62,20 +62,6 @@ import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
|
||||
this.isFinal = isFinal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of this instance with the period identifier's period index set to the specified
|
||||
* value.
|
||||
*/
|
||||
public MediaPeriodInfo copyWithPeriodIndex(int periodIndex) {
|
||||
return new MediaPeriodInfo(
|
||||
id.copyWithPeriodIndex(periodIndex),
|
||||
startPositionUs,
|
||||
contentPositionUs,
|
||||
durationUs,
|
||||
isLastInTimelinePeriod,
|
||||
isFinal);
|
||||
}
|
||||
|
||||
/** Returns a copy of this instance with the start position set to the specified value. */
|
||||
public MediaPeriodInfo copyWithStartPositionUs(long startPositionUs) {
|
||||
return new MediaPeriodInfo(
|
||||
|
@ -30,7 +30,6 @@ import com.google.android.exoplayer2.util.Assertions;
|
||||
* loading media period at the end of the queue, with methods for controlling loading and updating
|
||||
* the queue. Also has a reference to the media period currently being read.
|
||||
*/
|
||||
@SuppressWarnings("UngroupedOverloads")
|
||||
/* package */ final class MediaPeriodQueue {
|
||||
|
||||
/**
|
||||
@ -135,7 +134,6 @@ import com.google.android.exoplayer2.util.Assertions;
|
||||
* @param trackSelector The track selector.
|
||||
* @param allocator The allocator.
|
||||
* @param mediaSource The media source that produced the media period.
|
||||
* @param uid The unique identifier for the containing timeline period.
|
||||
* @param info Information used to identify this media period in its timeline period.
|
||||
*/
|
||||
public MediaPeriod enqueueNextMediaPeriod(
|
||||
@ -143,7 +141,6 @@ import com.google.android.exoplayer2.util.Assertions;
|
||||
TrackSelector trackSelector,
|
||||
Allocator allocator,
|
||||
MediaSource mediaSource,
|
||||
Object uid,
|
||||
MediaPeriodInfo info) {
|
||||
long rendererPositionOffsetUs =
|
||||
loading == null
|
||||
@ -156,7 +153,6 @@ import com.google.android.exoplayer2.util.Assertions;
|
||||
trackSelector,
|
||||
allocator,
|
||||
mediaSource,
|
||||
uid,
|
||||
info);
|
||||
if (loading != null) {
|
||||
Assertions.checkState(hasPlayingPeriod());
|
||||
@ -304,14 +300,14 @@ import com.google.android.exoplayer2.util.Assertions;
|
||||
// TODO: Merge this into setTimeline so that the queue gets updated as soon as the new timeline
|
||||
// is set, once all cases handled by ExoPlayerImplInternal.handleSourceInfoRefreshed can be
|
||||
// handled here.
|
||||
int periodIndex = playingPeriodId.periodIndex;
|
||||
int periodIndex = timeline.getIndexOfPeriod(playingPeriodId.periodUid);
|
||||
// The front period is either playing now, or is being loaded and will become the playing
|
||||
// period.
|
||||
MediaPeriodHolder previousPeriodHolder = null;
|
||||
MediaPeriodHolder periodHolder = getFrontPeriod();
|
||||
while (periodHolder != null) {
|
||||
if (previousPeriodHolder == null) {
|
||||
periodHolder.info = getUpdatedMediaPeriodInfo(periodHolder.info, periodIndex);
|
||||
periodHolder.info = getUpdatedMediaPeriodInfo(periodHolder.info);
|
||||
} else {
|
||||
// Check this period holder still follows the previous one, based on the new timeline.
|
||||
if (periodIndex == C.INDEX_UNSET
|
||||
@ -325,8 +321,8 @@ import com.google.android.exoplayer2.util.Assertions;
|
||||
// We've loaded a next media period that is not in the new timeline.
|
||||
return !removeAfter(previousPeriodHolder);
|
||||
}
|
||||
// Update the period index.
|
||||
periodHolder.info = getUpdatedMediaPeriodInfo(periodHolder.info, periodIndex);
|
||||
// Update the period holder.
|
||||
periodHolder.info = getUpdatedMediaPeriodInfo(periodHolder.info);
|
||||
// Check the media period information matches the new timeline.
|
||||
if (!canKeepMediaPeriodHolder(periodHolder, periodInfo)) {
|
||||
return !removeAfter(previousPeriodHolder);
|
||||
@ -348,16 +344,29 @@ import com.google.android.exoplayer2.util.Assertions;
|
||||
|
||||
/**
|
||||
* Returns new media period info based on specified {@code mediaPeriodInfo} but taking into
|
||||
* account the current timeline, and with the period index updated to {@code newPeriodIndex}.
|
||||
* account the current timeline. This method must only be called if the period is still part of
|
||||
* the current timeline.
|
||||
*
|
||||
* @param mediaPeriodInfo Media period info for a media period based on an old timeline.
|
||||
* @param newPeriodIndex The new period index in the new timeline for the existing media period.
|
||||
* @param info Media period info for a media period based on an old timeline.
|
||||
* @return The updated media period info for the current timeline.
|
||||
*/
|
||||
public MediaPeriodInfo getUpdatedMediaPeriodInfo(
|
||||
MediaPeriodInfo mediaPeriodInfo, int newPeriodIndex) {
|
||||
return getUpdatedMediaPeriodInfo(
|
||||
mediaPeriodInfo, mediaPeriodInfo.id.copyWithPeriodIndex(newPeriodIndex));
|
||||
public MediaPeriodInfo getUpdatedMediaPeriodInfo(MediaPeriodInfo info) {
|
||||
boolean isLastInPeriod = isLastInPeriod(info.id);
|
||||
boolean isLastInTimeline = isLastInTimeline(info.id, isLastInPeriod);
|
||||
timeline.getPeriodByUid(info.id.periodUid, period);
|
||||
long durationUs =
|
||||
info.id.isAd()
|
||||
? period.getAdDurationUs(info.id.adGroupIndex, info.id.adIndexInAdGroup)
|
||||
: (info.id.endPositionUs == C.TIME_END_OF_SOURCE
|
||||
? period.getDurationUs()
|
||||
: info.id.endPositionUs);
|
||||
return new MediaPeriodInfo(
|
||||
info.id,
|
||||
info.startPositionUs,
|
||||
info.contentPositionUs,
|
||||
durationUs,
|
||||
isLastInPeriod,
|
||||
isLastInTimeline);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -365,13 +374,13 @@ import com.google.android.exoplayer2.util.Assertions;
|
||||
* played, returning an identifier for an ad group if one needs to be played before the specified
|
||||
* position, or an identifier for a content media period if not.
|
||||
*
|
||||
* @param periodIndex The index of the timeline period to play.
|
||||
* @param periodUid The uid of the timeline period to play.
|
||||
* @param positionUs The next content position in the period to play.
|
||||
* @return The identifier for the first media period to play, taking into account unplayed ads.
|
||||
*/
|
||||
public MediaPeriodId resolveMediaPeriodIdForAds(int periodIndex, long positionUs) {
|
||||
long windowSequenceNumber = resolvePeriodIndexToWindowSequenceNumber(periodIndex);
|
||||
return resolveMediaPeriodIdForAds(periodIndex, positionUs, windowSequenceNumber);
|
||||
public MediaPeriodId resolveMediaPeriodIdForAds(Object periodUid, long positionUs) {
|
||||
long windowSequenceNumber = resolvePeriodIndexToWindowSequenceNumber(periodUid);
|
||||
return resolveMediaPeriodIdForAds(periodUid, positionUs, windowSequenceNumber);
|
||||
}
|
||||
|
||||
// Internal methods.
|
||||
@ -381,15 +390,15 @@ import com.google.android.exoplayer2.util.Assertions;
|
||||
* played, returning an identifier for an ad group if one needs to be played before the specified
|
||||
* position, or an identifier for a content media period if not.
|
||||
*
|
||||
* @param periodIndex The index of the timeline period to play.
|
||||
* @param periodUid The uid of the timeline period to play.
|
||||
* @param positionUs The next content position in the period to play.
|
||||
* @param windowSequenceNumber The sequence number of the window in the buffered sequence of
|
||||
* windows this period is part of.
|
||||
* @return The identifier for the first media period to play, taking into account unplayed ads.
|
||||
*/
|
||||
private MediaPeriodId resolveMediaPeriodIdForAds(
|
||||
int periodIndex, long positionUs, long windowSequenceNumber) {
|
||||
timeline.getPeriod(periodIndex, period);
|
||||
Object periodUid, long positionUs, long windowSequenceNumber) {
|
||||
timeline.getPeriodByUid(periodUid, period);
|
||||
int adGroupIndex = period.getAdGroupIndexForPositionUs(positionUs);
|
||||
if (adGroupIndex == C.INDEX_UNSET) {
|
||||
int nextAdGroupIndex = period.getAdGroupIndexAfterPositionUs(positionUs);
|
||||
@ -397,24 +406,23 @@ import com.google.android.exoplayer2.util.Assertions;
|
||||
nextAdGroupIndex == C.INDEX_UNSET
|
||||
? C.TIME_END_OF_SOURCE
|
||||
: period.getAdGroupTimeUs(nextAdGroupIndex);
|
||||
return new MediaPeriodId(periodIndex, windowSequenceNumber, endPositionUs);
|
||||
return new MediaPeriodId(periodUid, windowSequenceNumber, endPositionUs);
|
||||
} else {
|
||||
int adIndexInAdGroup = period.getFirstAdIndexToPlay(adGroupIndex);
|
||||
return new MediaPeriodId(periodIndex, adGroupIndex, adIndexInAdGroup, windowSequenceNumber);
|
||||
return new MediaPeriodId(periodUid, adGroupIndex, adIndexInAdGroup, windowSequenceNumber);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the specified period index to a corresponding window sequence number. Either by
|
||||
* reusing the window sequence number of an existing matching media period or by creating a new
|
||||
* window sequence number.
|
||||
* Resolves the specified period uid to a corresponding window sequence number. Either by reusing
|
||||
* the window sequence number of an existing matching media period or by creating a new window
|
||||
* sequence number.
|
||||
*
|
||||
* @param periodIndex The index of the timeline period.
|
||||
* @param periodUid The uid of the timeline period.
|
||||
* @return A window sequence number for a media period created for this timeline period.
|
||||
*/
|
||||
private long resolvePeriodIndexToWindowSequenceNumber(int periodIndex) {
|
||||
Object periodUid = timeline.getPeriod(periodIndex, period, /* setIds= */ true).uid;
|
||||
int windowIndex = period.windowIndex;
|
||||
private long resolvePeriodIndexToWindowSequenceNumber(Object periodUid) {
|
||||
int windowIndex = timeline.getPeriodByUid(periodUid, period).windowIndex;
|
||||
if (oldFrontPeriodUid != null) {
|
||||
int oldFrontPeriodIndex = timeline.getIndexOfPeriod(oldFrontPeriodUid);
|
||||
if (oldFrontPeriodIndex != C.INDEX_UNSET) {
|
||||
@ -469,32 +477,32 @@ import com.google.android.exoplayer2.util.Assertions;
|
||||
if (lastValidPeriodHolder == null) {
|
||||
return true;
|
||||
}
|
||||
int currentPeriodIndex = timeline.getIndexOfPeriod(lastValidPeriodHolder.uid);
|
||||
while (true) {
|
||||
int nextPeriodIndex =
|
||||
timeline.getNextPeriodIndex(
|
||||
lastValidPeriodHolder.info.id.periodIndex,
|
||||
period,
|
||||
window,
|
||||
repeatMode,
|
||||
shuffleModeEnabled);
|
||||
currentPeriodIndex, period, window, repeatMode, shuffleModeEnabled);
|
||||
while (lastValidPeriodHolder.next != null
|
||||
&& !lastValidPeriodHolder.info.isLastInTimelinePeriod) {
|
||||
lastValidPeriodHolder = lastValidPeriodHolder.next;
|
||||
}
|
||||
if (nextPeriodIndex == C.INDEX_UNSET
|
||||
|| lastValidPeriodHolder.next == null
|
||||
|| lastValidPeriodHolder.next.info.id.periodIndex != nextPeriodIndex) {
|
||||
|
||||
if (nextPeriodIndex == C.INDEX_UNSET || lastValidPeriodHolder.next == null) {
|
||||
break;
|
||||
}
|
||||
int nextPeriodHolderPeriodIndex = timeline.getIndexOfPeriod(lastValidPeriodHolder.next.uid);
|
||||
if (nextPeriodHolderPeriodIndex != nextPeriodIndex) {
|
||||
break;
|
||||
}
|
||||
lastValidPeriodHolder = lastValidPeriodHolder.next;
|
||||
currentPeriodIndex = nextPeriodIndex;
|
||||
}
|
||||
|
||||
// Release any period holders that don't match the new period order.
|
||||
boolean readingPeriodRemoved = removeAfter(lastValidPeriodHolder);
|
||||
|
||||
// Update the period info for the last holder, as it may now be the last period in the timeline.
|
||||
lastValidPeriodHolder.info =
|
||||
getUpdatedMediaPeriodInfo(lastValidPeriodHolder.info, lastValidPeriodHolder.info.id);
|
||||
lastValidPeriodHolder.info = getUpdatedMediaPeriodInfo(lastValidPeriodHolder.info);
|
||||
|
||||
// If renderers may have read from a period that's been removed, it is necessary to restart.
|
||||
return !readingPeriodRemoved || !hasPlayingPeriod();
|
||||
@ -525,9 +533,10 @@ import com.google.android.exoplayer2.util.Assertions;
|
||||
// timeline is updated, to avoid repeatedly checking the same timeline.
|
||||
MediaPeriodInfo mediaPeriodInfo = mediaPeriodHolder.info;
|
||||
if (mediaPeriodInfo.isLastInTimelinePeriod) {
|
||||
int currentPeriodIndex = timeline.getIndexOfPeriod(mediaPeriodInfo.id.periodUid);
|
||||
int nextPeriodIndex =
|
||||
timeline.getNextPeriodIndex(
|
||||
mediaPeriodInfo.id.periodIndex, period, window, repeatMode, shuffleModeEnabled);
|
||||
currentPeriodIndex, period, window, repeatMode, shuffleModeEnabled);
|
||||
if (nextPeriodIndex == C.INDEX_UNSET) {
|
||||
// We can't create a next period yet.
|
||||
return null;
|
||||
@ -546,7 +555,7 @@ import com.google.android.exoplayer2.util.Assertions;
|
||||
// the buffer, and start buffering from this point.
|
||||
long defaultPositionProjectionUs =
|
||||
mediaPeriodHolder.getRendererOffset() + mediaPeriodInfo.durationUs - rendererPositionUs;
|
||||
Pair<Integer, Long> defaultPosition =
|
||||
Pair<Object, Long> defaultPosition =
|
||||
timeline.getPeriodPosition(
|
||||
window,
|
||||
period,
|
||||
@ -556,7 +565,7 @@ import com.google.android.exoplayer2.util.Assertions;
|
||||
if (defaultPosition == null) {
|
||||
return null;
|
||||
}
|
||||
nextPeriodIndex = defaultPosition.first;
|
||||
nextPeriodUid = defaultPosition.first;
|
||||
startPositionUs = defaultPosition.second;
|
||||
if (mediaPeriodHolder.next != null && mediaPeriodHolder.next.uid.equals(nextPeriodUid)) {
|
||||
windowSequenceNumber = mediaPeriodHolder.next.info.id.windowSequenceNumber;
|
||||
@ -567,12 +576,12 @@ import com.google.android.exoplayer2.util.Assertions;
|
||||
startPositionUs = 0;
|
||||
}
|
||||
MediaPeriodId periodId =
|
||||
resolveMediaPeriodIdForAds(nextPeriodIndex, startPositionUs, windowSequenceNumber);
|
||||
resolveMediaPeriodIdForAds(nextPeriodUid, startPositionUs, windowSequenceNumber);
|
||||
return getMediaPeriodInfo(periodId, startPositionUs, startPositionUs);
|
||||
}
|
||||
|
||||
MediaPeriodId currentPeriodId = mediaPeriodInfo.id;
|
||||
timeline.getPeriod(currentPeriodId.periodIndex, period);
|
||||
timeline.getPeriodByUid(currentPeriodId.periodUid, period);
|
||||
if (currentPeriodId.isAd()) {
|
||||
int adGroupIndex = currentPeriodId.adGroupIndex;
|
||||
int adCountInCurrentAdGroup = period.getAdCountInAdGroup(adGroupIndex);
|
||||
@ -586,7 +595,7 @@ import com.google.android.exoplayer2.util.Assertions;
|
||||
return !period.isAdAvailable(adGroupIndex, nextAdIndexInAdGroup)
|
||||
? null
|
||||
: getMediaPeriodInfoForAd(
|
||||
currentPeriodId.periodIndex,
|
||||
currentPeriodId.periodUid,
|
||||
adGroupIndex,
|
||||
nextAdIndexInAdGroup,
|
||||
mediaPeriodInfo.contentPositionUs,
|
||||
@ -594,7 +603,7 @@ import com.google.android.exoplayer2.util.Assertions;
|
||||
} else {
|
||||
// Play content from the ad group position.
|
||||
return getMediaPeriodInfoForContent(
|
||||
currentPeriodId.periodIndex,
|
||||
currentPeriodId.periodUid,
|
||||
mediaPeriodInfo.contentPositionUs,
|
||||
currentPeriodId.windowSequenceNumber);
|
||||
}
|
||||
@ -604,7 +613,7 @@ import com.google.android.exoplayer2.util.Assertions;
|
||||
if (nextAdGroupIndex == C.INDEX_UNSET) {
|
||||
// The next ad group can't be played. Play content from the ad group position instead.
|
||||
return getMediaPeriodInfoForContent(
|
||||
currentPeriodId.periodIndex,
|
||||
currentPeriodId.periodUid,
|
||||
mediaPeriodInfo.id.endPositionUs,
|
||||
currentPeriodId.windowSequenceNumber);
|
||||
}
|
||||
@ -612,7 +621,7 @@ import com.google.android.exoplayer2.util.Assertions;
|
||||
return !period.isAdAvailable(nextAdGroupIndex, adIndexInAdGroup)
|
||||
? null
|
||||
: getMediaPeriodInfoForAd(
|
||||
currentPeriodId.periodIndex,
|
||||
currentPeriodId.periodUid,
|
||||
nextAdGroupIndex,
|
||||
adIndexInAdGroup,
|
||||
mediaPeriodInfo.id.endPositionUs,
|
||||
@ -634,7 +643,7 @@ import com.google.android.exoplayer2.util.Assertions;
|
||||
}
|
||||
long contentDurationUs = period.getDurationUs();
|
||||
return getMediaPeriodInfoForAd(
|
||||
currentPeriodId.periodIndex,
|
||||
currentPeriodId.periodUid,
|
||||
adGroupIndex,
|
||||
adIndexInAdGroup,
|
||||
contentDurationUs,
|
||||
@ -642,57 +651,37 @@ import com.google.android.exoplayer2.util.Assertions;
|
||||
}
|
||||
}
|
||||
|
||||
private MediaPeriodInfo getUpdatedMediaPeriodInfo(MediaPeriodInfo info, MediaPeriodId newId) {
|
||||
long startPositionUs = info.startPositionUs;
|
||||
boolean isLastInPeriod = isLastInPeriod(newId);
|
||||
boolean isLastInTimeline = isLastInTimeline(newId, isLastInPeriod);
|
||||
timeline.getPeriod(newId.periodIndex, period);
|
||||
long durationUs =
|
||||
newId.isAd()
|
||||
? period.getAdDurationUs(newId.adGroupIndex, newId.adIndexInAdGroup)
|
||||
: (newId.endPositionUs == C.TIME_END_OF_SOURCE
|
||||
? period.getDurationUs()
|
||||
: newId.endPositionUs);
|
||||
return new MediaPeriodInfo(
|
||||
newId,
|
||||
startPositionUs,
|
||||
info.contentPositionUs,
|
||||
durationUs,
|
||||
isLastInPeriod,
|
||||
isLastInTimeline);
|
||||
}
|
||||
|
||||
private MediaPeriodInfo getMediaPeriodInfo(
|
||||
MediaPeriodId id, long contentPositionUs, long startPositionUs) {
|
||||
timeline.getPeriod(id.periodIndex, period);
|
||||
timeline.getPeriodByUid(id.periodUid, period);
|
||||
if (id.isAd()) {
|
||||
if (!period.isAdAvailable(id.adGroupIndex, id.adIndexInAdGroup)) {
|
||||
return null;
|
||||
}
|
||||
return getMediaPeriodInfoForAd(
|
||||
id.periodIndex,
|
||||
id.periodUid,
|
||||
id.adGroupIndex,
|
||||
id.adIndexInAdGroup,
|
||||
contentPositionUs,
|
||||
id.windowSequenceNumber);
|
||||
} else {
|
||||
return getMediaPeriodInfoForContent(id.periodIndex, startPositionUs, id.windowSequenceNumber);
|
||||
return getMediaPeriodInfoForContent(id.periodUid, startPositionUs, id.windowSequenceNumber);
|
||||
}
|
||||
}
|
||||
|
||||
private MediaPeriodInfo getMediaPeriodInfoForAd(
|
||||
int periodIndex,
|
||||
Object periodUid,
|
||||
int adGroupIndex,
|
||||
int adIndexInAdGroup,
|
||||
long contentPositionUs,
|
||||
long windowSequenceNumber) {
|
||||
MediaPeriodId id =
|
||||
new MediaPeriodId(periodIndex, adGroupIndex, adIndexInAdGroup, windowSequenceNumber);
|
||||
new MediaPeriodId(periodUid, adGroupIndex, adIndexInAdGroup, windowSequenceNumber);
|
||||
boolean isLastInPeriod = isLastInPeriod(id);
|
||||
boolean isLastInTimeline = isLastInTimeline(id, isLastInPeriod);
|
||||
long durationUs =
|
||||
timeline
|
||||
.getPeriod(id.periodIndex, period)
|
||||
.getPeriodByUid(id.periodUid, period)
|
||||
.getAdDurationUs(id.adGroupIndex, id.adIndexInAdGroup);
|
||||
long startPositionUs =
|
||||
adIndexInAdGroup == period.getFirstAdIndexToPlay(adGroupIndex)
|
||||
@ -708,14 +697,14 @@ import com.google.android.exoplayer2.util.Assertions;
|
||||
}
|
||||
|
||||
private MediaPeriodInfo getMediaPeriodInfoForContent(
|
||||
int periodIndex, long startPositionUs, long windowSequenceNumber) {
|
||||
Object periodUid, long startPositionUs, long windowSequenceNumber) {
|
||||
int nextAdGroupIndex = period.getAdGroupIndexAfterPositionUs(startPositionUs);
|
||||
long endPositionUs =
|
||||
nextAdGroupIndex == C.INDEX_UNSET
|
||||
? C.TIME_END_OF_SOURCE
|
||||
: period.getAdGroupTimeUs(nextAdGroupIndex);
|
||||
MediaPeriodId id = new MediaPeriodId(periodIndex, windowSequenceNumber, endPositionUs);
|
||||
timeline.getPeriod(id.periodIndex, period);
|
||||
MediaPeriodId id = new MediaPeriodId(periodUid, windowSequenceNumber, endPositionUs);
|
||||
timeline.getPeriodByUid(id.periodUid, period);
|
||||
boolean isLastInPeriod = isLastInPeriod(id);
|
||||
boolean isLastInTimeline = isLastInTimeline(id, isLastInPeriod);
|
||||
long durationUs =
|
||||
@ -725,7 +714,7 @@ import com.google.android.exoplayer2.util.Assertions;
|
||||
}
|
||||
|
||||
private boolean isLastInPeriod(MediaPeriodId id) {
|
||||
int adGroupCount = timeline.getPeriod(id.periodIndex, period).getAdGroupCount();
|
||||
int adGroupCount = timeline.getPeriodByUid(id.periodUid, period).getAdGroupCount();
|
||||
if (adGroupCount == 0) {
|
||||
return true;
|
||||
}
|
||||
@ -749,9 +738,10 @@ import com.google.android.exoplayer2.util.Assertions;
|
||||
}
|
||||
|
||||
private boolean isLastInTimeline(MediaPeriodId id, boolean isLastMediaPeriodInPeriod) {
|
||||
int windowIndex = timeline.getPeriod(id.periodIndex, period).windowIndex;
|
||||
int periodIndex = timeline.getIndexOfPeriod(id.periodUid);
|
||||
int windowIndex = timeline.getPeriod(periodIndex, period).windowIndex;
|
||||
return !timeline.getWindow(windowIndex, window).isDynamic
|
||||
&& timeline.isLastPeriod(id.periodIndex, period, window, repeatMode, shuffleModeEnabled)
|
||||
&& timeline.isLastPeriod(periodIndex, period, window, repeatMode, shuffleModeEnabled)
|
||||
&& isLastMediaPeriodInPeriod;
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,8 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult;
|
||||
* Dummy media period id used while the timeline is empty and no period id is specified. This id
|
||||
* is used when playback infos are created with {@link #createDummy(long, TrackSelectorResult)}.
|
||||
*/
|
||||
public static final MediaPeriodId DUMMY_MEDIA_PERIOD_ID = new MediaPeriodId(/* periodIndex= */ 0);
|
||||
public static final MediaPeriodId DUMMY_MEDIA_PERIOD_ID =
|
||||
new MediaPeriodId(/* periodUid= */ new Object());
|
||||
|
||||
/** The current {@link Timeline}. */
|
||||
public final Timeline timeline;
|
||||
@ -149,23 +150,6 @@ import com.google.android.exoplayer2.trackselection.TrackSelectorResult;
|
||||
startPositionUs);
|
||||
}
|
||||
|
||||
public PlaybackInfo copyWithPeriodIndex(int periodIndex) {
|
||||
return new PlaybackInfo(
|
||||
timeline,
|
||||
manifest,
|
||||
periodId.copyWithPeriodIndex(periodIndex),
|
||||
startPositionUs,
|
||||
contentPositionUs,
|
||||
playbackState,
|
||||
isLoading,
|
||||
trackGroups,
|
||||
trackSelectorResult,
|
||||
loadingMediaPeriodId,
|
||||
bufferedPositionUs,
|
||||
totalBufferedDurationUs,
|
||||
positionUs);
|
||||
}
|
||||
|
||||
public PlaybackInfo copyWithTimeline(Timeline timeline, Object manifest) {
|
||||
return new PlaybackInfo(
|
||||
timeline,
|
||||
|
@ -702,13 +702,13 @@ public abstract class Timeline {
|
||||
* Calls {@link #getPeriodPosition(Window, Period, int, long, long)} with a zero default position
|
||||
* projection.
|
||||
*/
|
||||
public final Pair<Integer, Long> getPeriodPosition(Window window, Period period, int windowIndex,
|
||||
long windowPositionUs) {
|
||||
public final Pair<Object, Long> getPeriodPosition(
|
||||
Window window, Period period, int windowIndex, long windowPositionUs) {
|
||||
return getPeriodPosition(window, period, windowIndex, windowPositionUs, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts (windowIndex, windowPositionUs) to the corresponding (periodIndex, periodPositionUs).
|
||||
* Converts (windowIndex, windowPositionUs) to the corresponding (periodUid, periodPositionUs).
|
||||
*
|
||||
* @param window A {@link Window} that may be overwritten.
|
||||
* @param period A {@link Period} that may be overwritten.
|
||||
@ -717,12 +717,16 @@ public abstract class Timeline {
|
||||
* start position.
|
||||
* @param defaultPositionProjectionUs If {@code windowPositionUs} is {@link C#TIME_UNSET}, the
|
||||
* duration into the future by which the window's position should be projected.
|
||||
* @return The corresponding (periodIndex, periodPositionUs), or null if {@code #windowPositionUs}
|
||||
* @return The corresponding (periodUid, periodPositionUs), or null if {@code #windowPositionUs}
|
||||
* is {@link C#TIME_UNSET}, {@code defaultPositionProjectionUs} is non-zero, and the window's
|
||||
* position could not be projected by {@code defaultPositionProjectionUs}.
|
||||
*/
|
||||
public final Pair<Integer, Long> getPeriodPosition(Window window, Period period, int windowIndex,
|
||||
long windowPositionUs, long defaultPositionProjectionUs) {
|
||||
public final Pair<Object, Long> getPeriodPosition(
|
||||
Window window,
|
||||
Period period,
|
||||
int windowIndex,
|
||||
long windowPositionUs,
|
||||
long defaultPositionProjectionUs) {
|
||||
Assertions.checkIndex(windowIndex, 0, getWindowCount());
|
||||
getWindow(windowIndex, window, false, defaultPositionProjectionUs);
|
||||
if (windowPositionUs == C.TIME_UNSET) {
|
||||
@ -733,13 +737,13 @@ public abstract class Timeline {
|
||||
}
|
||||
int periodIndex = window.firstPeriodIndex;
|
||||
long periodPositionUs = window.getPositionInFirstPeriodUs() + windowPositionUs;
|
||||
long periodDurationUs = getPeriod(periodIndex, period).getDurationUs();
|
||||
long periodDurationUs = getPeriod(periodIndex, period, /* setIds= */ true).getDurationUs();
|
||||
while (periodDurationUs != C.TIME_UNSET && periodPositionUs >= periodDurationUs
|
||||
&& periodIndex < window.lastPeriodIndex) {
|
||||
periodPositionUs -= periodDurationUs;
|
||||
periodDurationUs = getPeriod(++periodIndex, period).getDurationUs();
|
||||
periodDurationUs = getPeriod(++periodIndex, period, /* setIds= */ true).getDurationUs();
|
||||
}
|
||||
return Pair.create(periodIndex, periodPositionUs);
|
||||
return Pair.create(period.uid, periodPositionUs);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -705,11 +705,10 @@ public class AnalyticsCollector
|
||||
public @Nullable MediaPeriodId tryResolveWindowIndex(int windowIndex) {
|
||||
MediaPeriodId match = null;
|
||||
if (timeline != null) {
|
||||
int timelinePeriodCount = timeline.getPeriodCount();
|
||||
for (int i = 0; i < activeMediaPeriods.size(); i++) {
|
||||
WindowAndMediaPeriodId mediaPeriod = activeMediaPeriods.get(i);
|
||||
int periodIndex = mediaPeriod.mediaPeriodId.periodIndex;
|
||||
if (periodIndex < timelinePeriodCount
|
||||
int periodIndex = timeline.getIndexOfPeriod(mediaPeriod.mediaPeriodId.periodUid);
|
||||
if (periodIndex != C.INDEX_UNSET
|
||||
&& timeline.getPeriod(periodIndex, period).windowIndex == windowIndex) {
|
||||
if (match != null) {
|
||||
// Ambiguous match.
|
||||
@ -731,10 +730,10 @@ public class AnalyticsCollector
|
||||
public void onTimelineChanged(Timeline timeline) {
|
||||
for (int i = 0; i < activeMediaPeriods.size(); i++) {
|
||||
activeMediaPeriods.set(
|
||||
i, updateMediaPeriodToNewTimeline(activeMediaPeriods.get(i), timeline));
|
||||
i, updateWindowIndexToNewTimeline(activeMediaPeriods.get(i), timeline));
|
||||
}
|
||||
if (readingMediaPeriod != null) {
|
||||
readingMediaPeriod = updateMediaPeriodToNewTimeline(readingMediaPeriod, timeline);
|
||||
readingMediaPeriod = updateWindowIndexToNewTimeline(readingMediaPeriod, timeline);
|
||||
}
|
||||
this.timeline = timeline;
|
||||
updateLastReportedPlayingMediaPeriod();
|
||||
@ -779,19 +778,17 @@ public class AnalyticsCollector
|
||||
}
|
||||
}
|
||||
|
||||
private WindowAndMediaPeriodId updateMediaPeriodToNewTimeline(
|
||||
private WindowAndMediaPeriodId updateWindowIndexToNewTimeline(
|
||||
WindowAndMediaPeriodId mediaPeriod, Timeline newTimeline) {
|
||||
if (newTimeline.isEmpty() || timeline.isEmpty()) {
|
||||
return mediaPeriod;
|
||||
}
|
||||
Object uid = timeline.getUidOfPeriod(mediaPeriod.mediaPeriodId.periodIndex);
|
||||
int newPeriodIndex = newTimeline.getIndexOfPeriod(uid);
|
||||
int newPeriodIndex = newTimeline.getIndexOfPeriod(mediaPeriod.mediaPeriodId.periodUid);
|
||||
if (newPeriodIndex == C.INDEX_UNSET) {
|
||||
return mediaPeriod;
|
||||
}
|
||||
int newWindowIndex = newTimeline.getPeriod(newPeriodIndex, period).windowIndex;
|
||||
return new WindowAndMediaPeriodId(
|
||||
newWindowIndex, mediaPeriod.mediaPeriodId.copyWithPeriodIndex(newPeriodIndex));
|
||||
return new WindowAndMediaPeriodId(newWindowIndex, mediaPeriod.mediaPeriodId);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,37 @@ import com.google.android.exoplayer2.Timeline;
|
||||
private final ShuffleOrder shuffleOrder;
|
||||
private final boolean isAtomic;
|
||||
|
||||
/**
|
||||
* Returns UID of child timeline from a concatenated period UID.
|
||||
*
|
||||
* @param concatenatedUid UID of a period in a concatenated timeline.
|
||||
* @return UID of the child timeline this period belongs to.
|
||||
*/
|
||||
public static Object getChildTimelineUidFromConcatenatedUid(Object concatenatedUid) {
|
||||
return ((Pair<?, ?>) concatenatedUid).first;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns UID of the period in the child timeline from a concatenated period UID.
|
||||
*
|
||||
* @param concatenatedUid UID of a period in a concatenated timeline.
|
||||
* @return UID of the period in the child timeline.
|
||||
*/
|
||||
public static Object getChildPeriodUidFromConcatenatedUid(Object concatenatedUid) {
|
||||
return ((Pair<?, ?>) concatenatedUid).second;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns concatenated UID for a period in a child timeline.
|
||||
*
|
||||
* @param childTimelineUid UID of the child timeline this period belongs to.
|
||||
* @param childPeriodUid UID of the period in the child timeline.
|
||||
* @return UID of the period in the concatenated timeline.
|
||||
*/
|
||||
public static Object getConcatenatedUid(Object childTimelineUid, Object childPeriodUid) {
|
||||
return Pair.create(childTimelineUid, childPeriodUid);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up a concatenated timeline with a shuffle order of child timelines.
|
||||
*
|
||||
@ -170,9 +201,8 @@ import com.google.android.exoplayer2.Timeline;
|
||||
|
||||
@Override
|
||||
public final Period getPeriodByUid(Object uid, Period period) {
|
||||
Pair<?, ?> childUidAndPeriodUid = (Pair<?, ?>) uid;
|
||||
Object childUid = childUidAndPeriodUid.first;
|
||||
Object periodUid = childUidAndPeriodUid.second;
|
||||
Object childUid = getChildTimelineUidFromConcatenatedUid(uid);
|
||||
Object periodUid = getChildPeriodUidFromConcatenatedUid(uid);
|
||||
int childIndex = getChildIndexByChildUid(childUid);
|
||||
int firstWindowIndexInChild = getFirstWindowIndexByChildIndex(childIndex);
|
||||
getTimelineByChildIndex(childIndex).getPeriodByUid(periodUid, period);
|
||||
@ -190,7 +220,7 @@ import com.google.android.exoplayer2.Timeline;
|
||||
setIds);
|
||||
period.windowIndex += firstWindowIndexInChild;
|
||||
if (setIds) {
|
||||
period.uid = Pair.create(getChildUidByChildIndex(childIndex), period.uid);
|
||||
period.uid = getConcatenatedUid(getChildUidByChildIndex(childIndex), period.uid);
|
||||
}
|
||||
return period;
|
||||
}
|
||||
@ -200,9 +230,8 @@ import com.google.android.exoplayer2.Timeline;
|
||||
if (!(uid instanceof Pair)) {
|
||||
return C.INDEX_UNSET;
|
||||
}
|
||||
Pair<?, ?> childUidAndPeriodUid = (Pair<?, ?>) uid;
|
||||
Object childUid = childUidAndPeriodUid.first;
|
||||
Object periodUid = childUidAndPeriodUid.second;
|
||||
Object childUid = getChildTimelineUidFromConcatenatedUid(uid);
|
||||
Object periodUid = getChildPeriodUidFromConcatenatedUid(uid);
|
||||
int childIndex = getChildIndexByChildUid(childUid);
|
||||
if (childIndex == C.INDEX_UNSET) {
|
||||
return C.INDEX_UNSET;
|
||||
@ -218,7 +247,7 @@ import com.google.android.exoplayer2.Timeline;
|
||||
int firstPeriodIndexInChild = getFirstPeriodIndexByChildIndex(childIndex);
|
||||
Object periodUidInChild =
|
||||
getTimelineByChildIndex(childIndex).getUidOfPeriod(periodIndex - firstPeriodIndexInChild);
|
||||
return Pair.create(getChildUidByChildIndex(childIndex), periodUidInChild);
|
||||
return getConcatenatedUid(getChildUidByChildIndex(childIndex), periodUidInChild);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -60,8 +60,8 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
|
||||
|
||||
// Accessed on the playback thread.
|
||||
private final List<MediaSourceHolder> mediaSourceHolders;
|
||||
private final MediaSourceHolder query;
|
||||
private final Map<MediaPeriod, MediaSourceHolder> mediaSourceByMediaPeriod;
|
||||
private final Map<Object, MediaSourceHolder> mediaSourceByUid;
|
||||
private final List<Runnable> pendingOnCompletionActions;
|
||||
private final boolean isAtomic;
|
||||
private final boolean useLazyPreparation;
|
||||
@ -125,10 +125,10 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
|
||||
}
|
||||
this.shuffleOrder = shuffleOrder.getLength() > 0 ? shuffleOrder.cloneAndClear() : shuffleOrder;
|
||||
this.mediaSourceByMediaPeriod = new IdentityHashMap<>();
|
||||
this.mediaSourceByUid = new HashMap<>();
|
||||
this.mediaSourcesPublic = new ArrayList<>();
|
||||
this.mediaSourceHolders = new ArrayList<>();
|
||||
this.pendingOnCompletionActions = new ArrayList<>();
|
||||
this.query = new MediaSourceHolder(/* mediaSource= */ null);
|
||||
this.isAtomic = isAtomic;
|
||||
this.useLazyPreparation = useLazyPreparation;
|
||||
window = new Timeline.Window();
|
||||
@ -451,8 +451,8 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
|
||||
|
||||
@Override
|
||||
public final MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) {
|
||||
int mediaSourceHolderIndex = findMediaSourceHolderByPeriodIndex(id.periodIndex);
|
||||
MediaSourceHolder holder = mediaSourceHolders.get(mediaSourceHolderIndex);
|
||||
Object mediaSourceHolderUid = getMediaSourceHolderUid(id.periodUid);
|
||||
MediaSourceHolder holder = Assertions.checkNotNull(mediaSourceByUid.get(mediaSourceHolderUid));
|
||||
DeferredMediaPeriod mediaPeriod = new DeferredMediaPeriod(holder.mediaSource, id, allocator);
|
||||
mediaSourceByMediaPeriod.put(mediaPeriod, holder);
|
||||
holder.activeMediaPeriods.add(mediaPeriod);
|
||||
@ -460,8 +460,7 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
|
||||
holder.hasStartedPreparing = true;
|
||||
prepareChildSource(holder, holder.mediaSource);
|
||||
} else if (holder.isPrepared) {
|
||||
MediaPeriodId idInSource =
|
||||
id.copyWithPeriodIndex(id.periodIndex - holder.firstPeriodIndexInChild);
|
||||
MediaPeriodId idInSource = id.copyWithPeriodUid(getChildPeriodUid(holder, id.periodUid));
|
||||
mediaPeriod.createPeriod(idInSource);
|
||||
}
|
||||
return mediaPeriod;
|
||||
@ -482,6 +481,7 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
|
||||
public final void releaseSourceInternal() {
|
||||
super.releaseSourceInternal();
|
||||
mediaSourceHolders.clear();
|
||||
mediaSourceByUid.clear();
|
||||
player = null;
|
||||
playerApplicationHandler = null;
|
||||
shuffleOrder = shuffleOrder.cloneAndClear();
|
||||
@ -506,8 +506,8 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
|
||||
// by this media source. Otherwise it does not belong to this child source.
|
||||
if (mediaSourceHolder.activeMediaPeriods.get(i).id.windowSequenceNumber
|
||||
== mediaPeriodId.windowSequenceNumber) {
|
||||
return mediaPeriodId.copyWithPeriodIndex(
|
||||
mediaPeriodId.periodIndex + mediaSourceHolder.firstPeriodIndexInChild);
|
||||
Object periodUid = getPeriodUid(mediaSourceHolder, mediaPeriodId.periodUid);
|
||||
return mediaPeriodId.copyWithPeriodUid(periodUid);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@ -633,6 +633,7 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
|
||||
newMediaSourceHolder.timeline.getWindowCount(),
|
||||
newMediaSourceHolder.timeline.getPeriodCount());
|
||||
mediaSourceHolders.add(newIndex, newMediaSourceHolder);
|
||||
mediaSourceByUid.put(newMediaSourceHolder.uid, newMediaSourceHolder);
|
||||
if (!useLazyPreparation) {
|
||||
newMediaSourceHolder.hasStartedPreparing = true;
|
||||
prepareChildSource(newMediaSourceHolder, newMediaSourceHolder.mediaSource);
|
||||
@ -672,8 +673,8 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
|
||||
DeferredMediaPeriod deferredMediaPeriod = mediaSourceHolder.activeMediaPeriods.get(i);
|
||||
deferredMediaPeriod.setDefaultPreparePositionUs(defaultPeriodPositionUs);
|
||||
MediaPeriodId idInSource =
|
||||
deferredMediaPeriod.id.copyWithPeriodIndex(
|
||||
deferredMediaPeriod.id.periodIndex - mediaSourceHolder.firstPeriodIndexInChild);
|
||||
deferredMediaPeriod.id.copyWithPeriodUid(
|
||||
getChildPeriodUid(mediaSourceHolder, deferredMediaPeriod.id.periodUid));
|
||||
deferredMediaPeriod.createPeriod(idInSource);
|
||||
}
|
||||
mediaSourceHolder.isPrepared = true;
|
||||
@ -689,6 +690,7 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
|
||||
|
||||
private void removeMediaSourceInternal(int index) {
|
||||
MediaSourceHolder holder = mediaSourceHolders.remove(index);
|
||||
mediaSourceByUid.remove(holder.uid);
|
||||
Timeline oldTimeline = holder.timeline;
|
||||
correctOffsets(
|
||||
index,
|
||||
@ -727,17 +729,22 @@ public class ConcatenatingMediaSource extends CompositeMediaSource<MediaSourceHo
|
||||
}
|
||||
}
|
||||
|
||||
private int findMediaSourceHolderByPeriodIndex(int periodIndex) {
|
||||
query.firstPeriodIndexInChild = periodIndex;
|
||||
int index = Collections.binarySearch(mediaSourceHolders, query);
|
||||
if (index < 0) {
|
||||
return -index - 2;
|
||||
/** Return uid of media source holder from period uid of concatenated source. */
|
||||
private static Object getMediaSourceHolderUid(Object periodUid) {
|
||||
return ConcatenatedTimeline.getChildTimelineUidFromConcatenatedUid(periodUid);
|
||||
}
|
||||
|
||||
/** Return uid of child period from period uid of concatenated source. */
|
||||
private static Object getChildPeriodUid(MediaSourceHolder holder, Object periodUid) {
|
||||
Object childUid = ConcatenatedTimeline.getChildPeriodUidFromConcatenatedUid(periodUid);
|
||||
return childUid.equals(DeferredTimeline.DUMMY_ID) ? holder.timeline.replacedId : childUid;
|
||||
}
|
||||
|
||||
private static Object getPeriodUid(MediaSourceHolder holder, Object childPeriodUid) {
|
||||
if (holder.timeline.replacedId.equals(childPeriodUid)) {
|
||||
childPeriodUid = DeferredTimeline.DUMMY_ID;
|
||||
}
|
||||
while (index < mediaSourceHolders.size() - 1
|
||||
&& mediaSourceHolders.get(index + 1).firstPeriodIndexInChild == periodIndex) {
|
||||
index++;
|
||||
}
|
||||
return index;
|
||||
return ConcatenatedTimeline.getConcatenatedUid(holder.uid, childPeriodUid);
|
||||
}
|
||||
|
||||
/** Data class to hold playlist media sources together with meta data needed to process them. */
|
||||
|
@ -371,7 +371,6 @@ public final class ExtractorMediaSource extends BaseMediaSource
|
||||
|
||||
@Override
|
||||
public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) {
|
||||
Assertions.checkArgument(id.periodIndex == 0);
|
||||
DataSource dataSource = dataSourceFactory.createDataSource();
|
||||
if (transferListener != null) {
|
||||
dataSource.addTransferListener(transferListener);
|
||||
|
@ -40,8 +40,6 @@ public final class LoopingMediaSource extends CompositeMediaSource<Void> {
|
||||
private final Map<MediaPeriodId, MediaPeriodId> childMediaPeriodIdToMediaPeriodId;
|
||||
private final Map<MediaPeriod, MediaPeriodId> mediaPeriodToChildMediaPeriodId;
|
||||
|
||||
private int childPeriodCount;
|
||||
|
||||
/**
|
||||
* Loops the provided source indefinitely. Note that it is usually better to use
|
||||
* {@link ExoPlayer#setRepeatMode(int)}.
|
||||
@ -80,7 +78,8 @@ public final class LoopingMediaSource extends CompositeMediaSource<Void> {
|
||||
if (loopCount == Integer.MAX_VALUE) {
|
||||
return childSource.createPeriod(id, allocator);
|
||||
}
|
||||
MediaPeriodId childMediaPeriodId = id.copyWithPeriodIndex(id.periodIndex % childPeriodCount);
|
||||
Object childPeriodUid = LoopingTimeline.getChildPeriodUidFromConcatenatedUid(id.periodUid);
|
||||
MediaPeriodId childMediaPeriodId = id.copyWithPeriodUid(childPeriodUid);
|
||||
childMediaPeriodIdToMediaPeriodId.put(childMediaPeriodId, id);
|
||||
MediaPeriod mediaPeriod = childSource.createPeriod(childMediaPeriodId, allocator);
|
||||
mediaPeriodToChildMediaPeriodId.put(mediaPeriod, childMediaPeriodId);
|
||||
@ -96,16 +95,9 @@ public final class LoopingMediaSource extends CompositeMediaSource<Void> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releaseSourceInternal() {
|
||||
super.releaseSourceInternal();
|
||||
childPeriodCount = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onChildSourceInfoRefreshed(
|
||||
Void id, MediaSource mediaSource, Timeline timeline, @Nullable Object manifest) {
|
||||
childPeriodCount = timeline.getPeriodCount();
|
||||
Timeline loopingTimeline =
|
||||
loopCount != Integer.MAX_VALUE
|
||||
? new LoopingTimeline(timeline, loopCount)
|
||||
|
@ -66,10 +66,8 @@ public interface MediaSource {
|
||||
*/
|
||||
final class MediaPeriodId {
|
||||
|
||||
/**
|
||||
* The timeline period index.
|
||||
*/
|
||||
public final int periodIndex;
|
||||
/** 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.
|
||||
@ -103,72 +101,70 @@ public interface MediaSource {
|
||||
* Creates a media period identifier for a dummy period which is not part of a buffered sequence
|
||||
* of windows.
|
||||
*
|
||||
* @param periodIndex The period index.
|
||||
* @param periodUid The unique id of the timeline period.
|
||||
*/
|
||||
public MediaPeriodId(int periodIndex) {
|
||||
this(periodIndex, C.INDEX_UNSET);
|
||||
public MediaPeriodId(Object periodUid) {
|
||||
this(periodUid, C.INDEX_UNSET);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a media period identifier for the specified period in the timeline.
|
||||
*
|
||||
* @param periodIndex The timeline period index.
|
||||
* @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(int periodIndex, long windowSequenceNumber) {
|
||||
this(periodIndex, C.INDEX_UNSET, C.INDEX_UNSET, windowSequenceNumber, C.TIME_END_OF_SOURCE);
|
||||
public MediaPeriodId(Object periodUid, long windowSequenceNumber) {
|
||||
this(periodUid, C.INDEX_UNSET, C.INDEX_UNSET, windowSequenceNumber, C.TIME_END_OF_SOURCE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a media period identifier for the specified clipped period in the timeline.
|
||||
*
|
||||
* @param periodIndex The timeline period index.
|
||||
* @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 endPositionUs The end position of the media period within the timeline period, in
|
||||
* microseconds.
|
||||
*/
|
||||
public MediaPeriodId(int periodIndex, long windowSequenceNumber, long endPositionUs) {
|
||||
this(periodIndex, C.INDEX_UNSET, C.INDEX_UNSET, windowSequenceNumber, endPositionUs);
|
||||
public MediaPeriodId(Object periodUid, long windowSequenceNumber, long endPositionUs) {
|
||||
this(periodUid, C.INDEX_UNSET, C.INDEX_UNSET, windowSequenceNumber, endPositionUs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a media period identifier that identifies an ad within an ad group at the specified
|
||||
* timeline period.
|
||||
*
|
||||
* @param periodIndex The index of the timeline period that contains the ad group.
|
||||
* @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(
|
||||
int periodIndex, int adGroupIndex, int adIndexInAdGroup, long windowSequenceNumber) {
|
||||
this(periodIndex, adGroupIndex, adIndexInAdGroup, windowSequenceNumber, C.TIME_END_OF_SOURCE);
|
||||
Object periodUid, int adGroupIndex, int adIndexInAdGroup, long windowSequenceNumber) {
|
||||
this(periodUid, adGroupIndex, adIndexInAdGroup, windowSequenceNumber, C.TIME_END_OF_SOURCE);
|
||||
}
|
||||
|
||||
private MediaPeriodId(
|
||||
int periodIndex,
|
||||
Object periodUid,
|
||||
int adGroupIndex,
|
||||
int adIndexInAdGroup,
|
||||
long windowSequenceNumber,
|
||||
long endPositionUs) {
|
||||
this.periodIndex = periodIndex;
|
||||
this.periodUid = periodUid;
|
||||
this.adGroupIndex = adGroupIndex;
|
||||
this.adIndexInAdGroup = adIndexInAdGroup;
|
||||
this.windowSequenceNumber = windowSequenceNumber;
|
||||
this.endPositionUs = endPositionUs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of this period identifier but with {@code newPeriodIndex} as its period index.
|
||||
*/
|
||||
public MediaPeriodId copyWithPeriodIndex(int newPeriodIndex) {
|
||||
return periodIndex == newPeriodIndex
|
||||
/** 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(
|
||||
newPeriodIndex, adGroupIndex, adIndexInAdGroup, windowSequenceNumber, endPositionUs);
|
||||
newPeriodUid, adGroupIndex, adIndexInAdGroup, windowSequenceNumber, endPositionUs);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -188,7 +184,7 @@ public interface MediaSource {
|
||||
}
|
||||
|
||||
MediaPeriodId periodId = (MediaPeriodId) obj;
|
||||
return periodIndex == periodId.periodIndex
|
||||
return periodUid.equals(periodId.periodUid)
|
||||
&& adGroupIndex == periodId.adGroupIndex
|
||||
&& adIndexInAdGroup == periodId.adIndexInAdGroup
|
||||
&& windowSequenceNumber == periodId.windowSequenceNumber
|
||||
@ -198,14 +194,13 @@ public interface MediaSource {
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = 17;
|
||||
result = 31 * result + periodIndex;
|
||||
result = 31 * result + periodUid.hashCode();
|
||||
result = 31 * result + adGroupIndex;
|
||||
result = 31 * result + adIndexInAdGroup;
|
||||
result = 31 * result + (int) windowSequenceNumber;
|
||||
result = 31 * result + (int) endPositionUs;
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -68,10 +68,10 @@ public final class MergingMediaSource extends CompositeMediaSource<Integer> {
|
||||
private static final int PERIOD_COUNT_UNSET = -1;
|
||||
|
||||
private final MediaSource[] mediaSources;
|
||||
private final Timeline[] timelines;
|
||||
private final ArrayList<MediaSource> pendingTimelineSources;
|
||||
private final CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
|
||||
|
||||
private Timeline primaryTimeline;
|
||||
private Object primaryManifest;
|
||||
private int periodCount;
|
||||
private IllegalMergeException mergeError;
|
||||
@ -95,6 +95,7 @@ public final class MergingMediaSource extends CompositeMediaSource<Integer> {
|
||||
this.compositeSequenceableLoaderFactory = compositeSequenceableLoaderFactory;
|
||||
pendingTimelineSources = new ArrayList<>(Arrays.asList(mediaSources));
|
||||
periodCount = PERIOD_COUNT_UNSET;
|
||||
timelines = new Timeline[mediaSources.length];
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -119,8 +120,11 @@ public final class MergingMediaSource extends CompositeMediaSource<Integer> {
|
||||
@Override
|
||||
public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) {
|
||||
MediaPeriod[] periods = new MediaPeriod[mediaSources.length];
|
||||
int periodIndex = timelines[0].getIndexOfPeriod(id.periodUid);
|
||||
for (int i = 0; i < periods.length; i++) {
|
||||
periods[i] = mediaSources[i].createPeriod(id, allocator);
|
||||
MediaPeriodId childMediaPeriodId =
|
||||
id.copyWithPeriodUid(timelines[i].getUidOfPeriod(periodIndex));
|
||||
periods[i] = mediaSources[i].createPeriod(childMediaPeriodId, allocator);
|
||||
}
|
||||
return new MergingMediaPeriod(compositeSequenceableLoaderFactory, periods);
|
||||
}
|
||||
@ -136,7 +140,7 @@ public final class MergingMediaSource extends CompositeMediaSource<Integer> {
|
||||
@Override
|
||||
public void releaseSourceInternal() {
|
||||
super.releaseSourceInternal();
|
||||
primaryTimeline = null;
|
||||
Arrays.fill(timelines, null);
|
||||
primaryManifest = null;
|
||||
periodCount = PERIOD_COUNT_UNSET;
|
||||
mergeError = null;
|
||||
@ -154,12 +158,12 @@ public final class MergingMediaSource extends CompositeMediaSource<Integer> {
|
||||
return;
|
||||
}
|
||||
pendingTimelineSources.remove(mediaSource);
|
||||
timelines[id] = timeline;
|
||||
if (mediaSource == mediaSources[0]) {
|
||||
primaryTimeline = timeline;
|
||||
primaryManifest = manifest;
|
||||
}
|
||||
if (pendingTimelineSources.isEmpty()) {
|
||||
refreshSourceInfo(primaryTimeline, primaryManifest);
|
||||
refreshSourceInfo(timelines[0], primaryManifest);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -308,7 +308,6 @@ public final class SingleSampleMediaSource extends BaseMediaSource {
|
||||
|
||||
@Override
|
||||
public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) {
|
||||
Assertions.checkArgument(id.periodIndex == 0);
|
||||
return new SingleSampleMediaPeriod(
|
||||
dataSpec,
|
||||
dataSourceFactory,
|
||||
|
@ -176,7 +176,7 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
|
||||
|
||||
// Used to identify the content "child" source for CompositeMediaSource.
|
||||
private static final MediaPeriodId DUMMY_CONTENT_MEDIA_PERIOD_ID =
|
||||
new MediaPeriodId(/* periodIndex= */ 0);
|
||||
new MediaPeriodId(/* periodUid= */ new Object());
|
||||
|
||||
private final MediaSource contentMediaSource;
|
||||
private final MediaSourceFactory adMediaSourceFactory;
|
||||
@ -194,7 +194,7 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
|
||||
private Object contentManifest;
|
||||
private AdPlaybackState adPlaybackState;
|
||||
private MediaSource[][] adGroupMediaSources;
|
||||
private long[][] adDurationsUs;
|
||||
private Timeline[][] adGroupTimelines;
|
||||
|
||||
/**
|
||||
* Constructs a new source that inserts ads linearly with the content specified by {@code
|
||||
@ -309,7 +309,7 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
|
||||
deferredMediaPeriodByAdMediaSource = new HashMap<>();
|
||||
period = new Timeline.Period();
|
||||
adGroupMediaSources = new MediaSource[0][];
|
||||
adDurationsUs = new long[0][];
|
||||
adGroupTimelines = new Timeline[0][];
|
||||
adsLoader.setSupportedContentTypes(adMediaSourceFactory.getSupportedTypes());
|
||||
}
|
||||
|
||||
@ -341,8 +341,7 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
|
||||
int adCount = adIndexInAdGroup + 1;
|
||||
adGroupMediaSources[adGroupIndex] =
|
||||
Arrays.copyOf(adGroupMediaSources[adGroupIndex], adCount);
|
||||
adDurationsUs[adGroupIndex] = Arrays.copyOf(adDurationsUs[adGroupIndex], adCount);
|
||||
Arrays.fill(adDurationsUs[adGroupIndex], oldAdCount, adCount, C.TIME_UNSET);
|
||||
adGroupTimelines[adGroupIndex] = Arrays.copyOf(adGroupTimelines[adGroupIndex], adCount);
|
||||
}
|
||||
adGroupMediaSources[adGroupIndex][adIndexInAdGroup] = adMediaSource;
|
||||
deferredMediaPeriodByAdMediaSource.put(adMediaSource, new ArrayList<>());
|
||||
@ -354,8 +353,9 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
|
||||
new AdPrepareErrorListener(adUri, adGroupIndex, adIndexInAdGroup));
|
||||
List<DeferredMediaPeriod> mediaPeriods = deferredMediaPeriodByAdMediaSource.get(mediaSource);
|
||||
if (mediaPeriods == null) {
|
||||
MediaPeriodId adSourceMediaPeriodId =
|
||||
new MediaPeriodId(/* periodIndex= */ 0, id.windowSequenceNumber);
|
||||
Object periodUid =
|
||||
adGroupTimelines[adGroupIndex][adIndexInAdGroup].getUidOfPeriod(/* periodIndex= */ 0);
|
||||
MediaPeriodId adSourceMediaPeriodId = new MediaPeriodId(periodUid, id.windowSequenceNumber);
|
||||
deferredMediaPeriod.createPeriod(adSourceMediaPeriodId);
|
||||
} else {
|
||||
// Keep track of the deferred media period so it can be populated with the real media period
|
||||
@ -391,7 +391,7 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
|
||||
contentManifest = null;
|
||||
adPlaybackState = null;
|
||||
adGroupMediaSources = new MediaSource[0][];
|
||||
adDurationsUs = new long[0][];
|
||||
adGroupTimelines = new Timeline[0][];
|
||||
mainHandler.post(adsLoader::detachPlayer);
|
||||
}
|
||||
|
||||
@ -424,8 +424,8 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
|
||||
if (this.adPlaybackState == null) {
|
||||
adGroupMediaSources = new MediaSource[adPlaybackState.adGroupCount][];
|
||||
Arrays.fill(adGroupMediaSources, new MediaSource[0]);
|
||||
adDurationsUs = new long[adPlaybackState.adGroupCount][];
|
||||
Arrays.fill(adDurationsUs, new long[0]);
|
||||
adGroupTimelines = new Timeline[adPlaybackState.adGroupCount][];
|
||||
Arrays.fill(adGroupTimelines, new Timeline[0]);
|
||||
}
|
||||
this.adPlaybackState = adPlaybackState;
|
||||
maybeUpdateSourceInfo();
|
||||
@ -440,13 +440,14 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
|
||||
private void onAdSourceInfoRefreshed(MediaSource mediaSource, int adGroupIndex,
|
||||
int adIndexInAdGroup, Timeline timeline) {
|
||||
Assertions.checkArgument(timeline.getPeriodCount() == 1);
|
||||
adDurationsUs[adGroupIndex][adIndexInAdGroup] = timeline.getPeriod(0, period).getDurationUs();
|
||||
adGroupTimelines[adGroupIndex][adIndexInAdGroup] = timeline;
|
||||
List<DeferredMediaPeriod> mediaPeriods = deferredMediaPeriodByAdMediaSource.remove(mediaSource);
|
||||
if (mediaPeriods != null) {
|
||||
Object periodUid = timeline.getUidOfPeriod(/* periodIndex= */ 0);
|
||||
for (int i = 0; i < mediaPeriods.size(); i++) {
|
||||
DeferredMediaPeriod mediaPeriod = mediaPeriods.get(i);
|
||||
MediaPeriodId adSourceMediaPeriodId =
|
||||
new MediaPeriodId(/* periodIndex= */ 0, mediaPeriod.id.windowSequenceNumber);
|
||||
new MediaPeriodId(periodUid, mediaPeriod.id.windowSequenceNumber);
|
||||
mediaPeriod.createPeriod(adSourceMediaPeriodId);
|
||||
}
|
||||
}
|
||||
@ -455,7 +456,7 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
|
||||
|
||||
private void maybeUpdateSourceInfo() {
|
||||
if (adPlaybackState != null && contentTimeline != null) {
|
||||
adPlaybackState = adPlaybackState.withAdDurationsUs(adDurationsUs);
|
||||
adPlaybackState = adPlaybackState.withAdDurationsUs(getAdDurations(adGroupTimelines, period));
|
||||
Timeline timeline =
|
||||
adPlaybackState.adGroupCount == 0
|
||||
? contentTimeline
|
||||
@ -464,6 +465,20 @@ public final class AdsMediaSource extends CompositeMediaSource<MediaPeriodId> {
|
||||
}
|
||||
}
|
||||
|
||||
private static long[][] getAdDurations(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];
|
||||
for (int j = 0; j < adTimelines[i].length; j++) {
|
||||
adDurations[i][j] =
|
||||
adTimelines[i][j] == null
|
||||
? C.TIME_UNSET
|
||||
: adTimelines[i][j].getPeriod(/* periodIndex= */ 0, period).getDurationUs();
|
||||
}
|
||||
}
|
||||
return adDurations;
|
||||
}
|
||||
|
||||
/** Listener for component events. All methods are called on the main thread. */
|
||||
private final class ComponentListener implements AdsLoader.EventListener {
|
||||
|
||||
|
@ -456,7 +456,8 @@ public class EventLogger implements AnalyticsListener {
|
||||
private String getEventTimeString(EventTime eventTime) {
|
||||
String windowPeriodString = "window=" + eventTime.windowIndex;
|
||||
if (eventTime.mediaPeriodId != null) {
|
||||
windowPeriodString += ", period=" + eventTime.mediaPeriodId.periodIndex;
|
||||
windowPeriodString +=
|
||||
", period=" + eventTime.timeline.getIndexOfPeriod(eventTime.mediaPeriodId.periodUid);
|
||||
if (eventTime.mediaPeriodId.isAd()) {
|
||||
windowPeriodString += ", adGroup=" + eventTime.mediaPeriodId.adGroupIndex;
|
||||
windowPeriodString += ", ad=" + eventTime.mediaPeriodId.adIndexInAdGroup;
|
||||
|
@ -187,10 +187,28 @@ public final class ExoPlayerTest {
|
||||
@Test
|
||||
public void testReadAheadToEndDoesNotResetRenderer() throws Exception {
|
||||
// Use sufficiently short periods to ensure the player attempts to read all at once.
|
||||
TimelineWindowDefinition windowDefinition =
|
||||
TimelineWindowDefinition windowDefinition0 =
|
||||
new TimelineWindowDefinition(
|
||||
/* isSeekable= */ false, /* isDynamic= */ false, /* durationUs= */ 100_000);
|
||||
Timeline timeline = new FakeTimeline(windowDefinition, windowDefinition, windowDefinition);
|
||||
/* periodCount= */ 1,
|
||||
/* id= */ 0,
|
||||
/* isSeekable= */ false,
|
||||
/* isDynamic= */ false,
|
||||
/* durationUs= */ 100_000);
|
||||
TimelineWindowDefinition windowDefinition1 =
|
||||
new TimelineWindowDefinition(
|
||||
/* periodCount= */ 1,
|
||||
/* id= */ 1,
|
||||
/* isSeekable= */ false,
|
||||
/* isDynamic= */ false,
|
||||
/* durationUs= */ 100_000);
|
||||
TimelineWindowDefinition windowDefinition2 =
|
||||
new TimelineWindowDefinition(
|
||||
/* periodCount= */ 1,
|
||||
/* id= */ 2,
|
||||
/* isSeekable= */ false,
|
||||
/* isDynamic= */ false,
|
||||
/* durationUs= */ 100_000);
|
||||
Timeline timeline = new FakeTimeline(windowDefinition0, windowDefinition1, windowDefinition2);
|
||||
final FakeRenderer videoRenderer = new FakeRenderer(Builder.VIDEO_FORMAT);
|
||||
FakeMediaClockRenderer audioRenderer =
|
||||
new FakeMediaClockRenderer(Builder.AUDIO_FORMAT) {
|
||||
@ -2019,9 +2037,12 @@ public final class ExoPlayerTest {
|
||||
// Assert that the second period was re-created from the new timeline.
|
||||
assertThat(mediaSource.getCreatedMediaPeriods())
|
||||
.containsExactly(
|
||||
new MediaPeriodId(/* periodIndex= */ 0, /* windowSequenceNumber= */ 0),
|
||||
new MediaPeriodId(/* periodIndex= */ 1, /* windowSequenceNumber= */ 1),
|
||||
new MediaPeriodId(/* periodIndex= */ 1, /* windowSequenceNumber= */ 2))
|
||||
new MediaPeriodId(
|
||||
timeline1.getUidOfPeriod(/* periodIndex= */ 0), /* windowSequenceNumber= */ 0),
|
||||
new MediaPeriodId(
|
||||
timeline1.getUidOfPeriod(/* periodIndex= */ 1), /* windowSequenceNumber= */ 1),
|
||||
new MediaPeriodId(
|
||||
timeline2.getUidOfPeriod(/* periodIndex= */ 1), /* windowSequenceNumber= */ 2))
|
||||
.inOrder();
|
||||
}
|
||||
|
||||
@ -2057,10 +2078,14 @@ public final class ExoPlayerTest {
|
||||
testRunner.assertPlayedPeriodIndices(0, 1, 0, 1);
|
||||
assertThat(mediaSource.getCreatedMediaPeriods())
|
||||
.containsAllOf(
|
||||
new MediaPeriodId(/* periodIndex= */ 0, /* windowSequenceNumber= */ 0),
|
||||
new MediaPeriodId(/* periodIndex= */ 1, /* windowSequenceNumber= */ 0));
|
||||
new MediaPeriodId(
|
||||
timeline.getUidOfPeriod(/* periodIndex= */ 0), /* windowSequenceNumber= */ 0),
|
||||
new MediaPeriodId(
|
||||
timeline.getUidOfPeriod(/* periodIndex= */ 1), /* windowSequenceNumber= */ 0));
|
||||
assertThat(mediaSource.getCreatedMediaPeriods())
|
||||
.doesNotContain(new MediaPeriodId(/* periodIndex= */ 1, /* windowSequenceNumber= */ 1));
|
||||
.doesNotContain(
|
||||
new MediaPeriodId(
|
||||
timeline.getUidOfPeriod(/* periodIndex= */ 1), /* windowSequenceNumber= */ 1));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -108,28 +108,16 @@ public final class AnalyticsCollectorTest {
|
||||
new EventWindowAndPeriodId(/* windowIndex= */ 0, /* mediaPeriodId= */ null);
|
||||
private static final EventWindowAndPeriodId WINDOW_1 =
|
||||
new EventWindowAndPeriodId(/* windowIndex= */ 1, /* mediaPeriodId= */ null);
|
||||
private static final EventWindowAndPeriodId PERIOD_0 =
|
||||
new EventWindowAndPeriodId(
|
||||
/* windowIndex= */ 0,
|
||||
new MediaPeriodId(/* periodIndex= */ 0, /* windowSequenceNumber= */ 0));
|
||||
private static final EventWindowAndPeriodId PERIOD_1 =
|
||||
new EventWindowAndPeriodId(
|
||||
/* windowIndex= */ 1,
|
||||
new MediaPeriodId(/* periodIndex= */ 1, /* windowSequenceNumber= */ 1));
|
||||
private static final EventWindowAndPeriodId PERIOD_0_SEQ_0 = PERIOD_0;
|
||||
private static final EventWindowAndPeriodId PERIOD_1_SEQ_1 = PERIOD_1;
|
||||
private static final EventWindowAndPeriodId PERIOD_0_SEQ_1 =
|
||||
new EventWindowAndPeriodId(
|
||||
/* windowIndex= */ 0,
|
||||
new MediaPeriodId(/* periodIndex= */ 0, /* windowSequenceNumber= */ 1));
|
||||
private static final EventWindowAndPeriodId PERIOD_1_SEQ_0 =
|
||||
new EventWindowAndPeriodId(
|
||||
/* windowIndex= */ 1,
|
||||
new MediaPeriodId(/* periodIndex= */ 1, /* windowSequenceNumber= */ 0));
|
||||
private static final EventWindowAndPeriodId PERIOD_1_SEQ_2 =
|
||||
new EventWindowAndPeriodId(
|
||||
/* windowIndex= */ 1,
|
||||
new MediaPeriodId(/* periodIndex= */ 1, /* windowSequenceNumber= */ 2));
|
||||
|
||||
private EventWindowAndPeriodId period0;
|
||||
private EventWindowAndPeriodId period1;
|
||||
private EventWindowAndPeriodId period0Seq0;
|
||||
private EventWindowAndPeriodId period1Seq1;
|
||||
private EventWindowAndPeriodId period0Seq1;
|
||||
private EventWindowAndPeriodId period1Seq0;
|
||||
private EventWindowAndPeriodId period1Seq2;
|
||||
private EventWindowAndPeriodId window0Period1Seq0;
|
||||
private EventWindowAndPeriodId window1Period0Seq1;
|
||||
|
||||
@Test
|
||||
public void testEmptyTimeline() throws Exception {
|
||||
@ -155,34 +143,35 @@ public final class AnalyticsCollectorTest {
|
||||
Builder.AUDIO_FORMAT);
|
||||
TestAnalyticsListener listener = runAnalyticsTest(mediaSource);
|
||||
|
||||
populateEventIds(SINGLE_PERIOD_TIMELINE);
|
||||
assertThat(listener.getEvents(EVENT_PLAYER_STATE_CHANGED))
|
||||
.containsExactly(
|
||||
WINDOW_0 /* setPlayWhenReady */,
|
||||
WINDOW_0 /* BUFFERING */,
|
||||
PERIOD_0 /* READY */,
|
||||
PERIOD_0 /* ENDED */);
|
||||
period0 /* READY */,
|
||||
period0 /* ENDED */);
|
||||
assertThat(listener.getEvents(EVENT_TIMELINE_CHANGED)).containsExactly(WINDOW_0);
|
||||
assertThat(listener.getEvents(EVENT_LOADING_CHANGED))
|
||||
.containsExactly(PERIOD_0 /* started */, PERIOD_0 /* stopped */);
|
||||
assertThat(listener.getEvents(EVENT_TRACKS_CHANGED)).containsExactly(PERIOD_0);
|
||||
.containsExactly(period0 /* started */, period0 /* stopped */);
|
||||
assertThat(listener.getEvents(EVENT_TRACKS_CHANGED)).containsExactly(period0);
|
||||
assertThat(listener.getEvents(EVENT_LOAD_STARTED))
|
||||
.containsExactly(WINDOW_0 /* manifest */, PERIOD_0 /* media */);
|
||||
.containsExactly(WINDOW_0 /* manifest */, period0 /* media */);
|
||||
assertThat(listener.getEvents(EVENT_LOAD_COMPLETED))
|
||||
.containsExactly(WINDOW_0 /* manifest */, PERIOD_0 /* media */);
|
||||
.containsExactly(WINDOW_0 /* manifest */, period0 /* media */);
|
||||
assertThat(listener.getEvents(EVENT_DOWNSTREAM_FORMAT_CHANGED))
|
||||
.containsExactly(PERIOD_0 /* audio */, PERIOD_0 /* video */);
|
||||
assertThat(listener.getEvents(EVENT_MEDIA_PERIOD_CREATED)).containsExactly(PERIOD_0);
|
||||
assertThat(listener.getEvents(EVENT_READING_STARTED)).containsExactly(PERIOD_0);
|
||||
.containsExactly(period0 /* audio */, period0 /* video */);
|
||||
assertThat(listener.getEvents(EVENT_MEDIA_PERIOD_CREATED)).containsExactly(period0);
|
||||
assertThat(listener.getEvents(EVENT_READING_STARTED)).containsExactly(period0);
|
||||
assertThat(listener.getEvents(EVENT_DECODER_ENABLED))
|
||||
.containsExactly(PERIOD_0 /* audio */, PERIOD_0 /* video */);
|
||||
.containsExactly(period0 /* audio */, period0 /* video */);
|
||||
assertThat(listener.getEvents(EVENT_DECODER_INIT))
|
||||
.containsExactly(PERIOD_0 /* audio */, PERIOD_0 /* video */);
|
||||
.containsExactly(period0 /* audio */, period0 /* video */);
|
||||
assertThat(listener.getEvents(EVENT_DECODER_FORMAT_CHANGED))
|
||||
.containsExactly(PERIOD_0 /* audio */, PERIOD_0 /* video */);
|
||||
assertThat(listener.getEvents(EVENT_AUDIO_SESSION_ID)).containsExactly(PERIOD_0);
|
||||
assertThat(listener.getEvents(EVENT_DROPPED_VIDEO_FRAMES)).containsExactly(PERIOD_0);
|
||||
assertThat(listener.getEvents(EVENT_VIDEO_SIZE_CHANGED)).containsExactly(PERIOD_0);
|
||||
assertThat(listener.getEvents(EVENT_RENDERED_FIRST_FRAME)).containsExactly(PERIOD_0);
|
||||
.containsExactly(period0 /* audio */, period0 /* video */);
|
||||
assertThat(listener.getEvents(EVENT_AUDIO_SESSION_ID)).containsExactly(period0);
|
||||
assertThat(listener.getEvents(EVENT_DROPPED_VIDEO_FRAMES)).containsExactly(period0);
|
||||
assertThat(listener.getEvents(EVENT_VIDEO_SIZE_CHANGED)).containsExactly(period0);
|
||||
assertThat(listener.getEvents(EVENT_RENDERED_FIRST_FRAME)).containsExactly(period0);
|
||||
listener.assertNoMoreEvents();
|
||||
}
|
||||
|
||||
@ -202,47 +191,48 @@ public final class AnalyticsCollectorTest {
|
||||
Builder.AUDIO_FORMAT));
|
||||
TestAnalyticsListener listener = runAnalyticsTest(mediaSource);
|
||||
|
||||
populateEventIds(listener.lastReportedTimeline);
|
||||
assertThat(listener.getEvents(EVENT_PLAYER_STATE_CHANGED))
|
||||
.containsExactly(
|
||||
WINDOW_0 /* setPlayWhenReady */,
|
||||
WINDOW_0 /* BUFFERING */,
|
||||
PERIOD_0 /* READY */,
|
||||
PERIOD_1 /* ENDED */);
|
||||
period0 /* READY */,
|
||||
period1 /* ENDED */);
|
||||
assertThat(listener.getEvents(EVENT_TIMELINE_CHANGED)).containsExactly(WINDOW_0);
|
||||
assertThat(listener.getEvents(EVENT_POSITION_DISCONTINUITY)).containsExactly(PERIOD_1);
|
||||
assertThat(listener.getEvents(EVENT_POSITION_DISCONTINUITY)).containsExactly(period1);
|
||||
assertThat(listener.getEvents(EVENT_LOADING_CHANGED))
|
||||
.containsExactly(PERIOD_0, PERIOD_0, PERIOD_0, PERIOD_0);
|
||||
assertThat(listener.getEvents(EVENT_TRACKS_CHANGED)).containsExactly(PERIOD_0, PERIOD_1);
|
||||
.containsExactly(period0, period0, period0, period0);
|
||||
assertThat(listener.getEvents(EVENT_TRACKS_CHANGED)).containsExactly(period0, period1);
|
||||
assertThat(listener.getEvents(EVENT_LOAD_STARTED))
|
||||
.containsExactly(
|
||||
WINDOW_0 /* manifest */,
|
||||
PERIOD_0 /* media */,
|
||||
period0 /* media */,
|
||||
WINDOW_1 /* manifest */,
|
||||
PERIOD_1 /* media */);
|
||||
period1 /* media */);
|
||||
assertThat(listener.getEvents(EVENT_LOAD_COMPLETED))
|
||||
.containsExactly(
|
||||
WINDOW_0 /* manifest */,
|
||||
PERIOD_0 /* media */,
|
||||
period0 /* media */,
|
||||
WINDOW_1 /* manifest */,
|
||||
PERIOD_1 /* media */);
|
||||
period1 /* media */);
|
||||
assertThat(listener.getEvents(EVENT_DOWNSTREAM_FORMAT_CHANGED))
|
||||
.containsExactly(
|
||||
PERIOD_0 /* audio */, PERIOD_0 /* video */, PERIOD_1 /* audio */, PERIOD_1 /* video */);
|
||||
assertThat(listener.getEvents(EVENT_MEDIA_PERIOD_CREATED)).containsExactly(PERIOD_0, PERIOD_1);
|
||||
assertThat(listener.getEvents(EVENT_MEDIA_PERIOD_RELEASED)).containsExactly(PERIOD_0);
|
||||
assertThat(listener.getEvents(EVENT_READING_STARTED)).containsExactly(PERIOD_0, PERIOD_1);
|
||||
period0 /* audio */, period0 /* video */, period1 /* audio */, period1 /* video */);
|
||||
assertThat(listener.getEvents(EVENT_MEDIA_PERIOD_CREATED)).containsExactly(period0, period1);
|
||||
assertThat(listener.getEvents(EVENT_MEDIA_PERIOD_RELEASED)).containsExactly(period0);
|
||||
assertThat(listener.getEvents(EVENT_READING_STARTED)).containsExactly(period0, period1);
|
||||
assertThat(listener.getEvents(EVENT_DECODER_ENABLED))
|
||||
.containsExactly(PERIOD_0 /* audio */, PERIOD_0 /* video */);
|
||||
.containsExactly(period0 /* audio */, period0 /* video */);
|
||||
assertThat(listener.getEvents(EVENT_DECODER_INIT))
|
||||
.containsExactly(
|
||||
PERIOD_0 /* audio */, PERIOD_0 /* video */, PERIOD_1 /* audio */, PERIOD_1 /* video */);
|
||||
period0 /* audio */, period0 /* video */, period1 /* audio */, period1 /* video */);
|
||||
assertThat(listener.getEvents(EVENT_DECODER_FORMAT_CHANGED))
|
||||
.containsExactly(
|
||||
PERIOD_0 /* audio */, PERIOD_0 /* video */, PERIOD_1 /* audio */, PERIOD_1 /* video */);
|
||||
assertThat(listener.getEvents(EVENT_AUDIO_SESSION_ID)).containsExactly(PERIOD_0);
|
||||
assertThat(listener.getEvents(EVENT_DROPPED_VIDEO_FRAMES)).containsExactly(PERIOD_1);
|
||||
assertThat(listener.getEvents(EVENT_VIDEO_SIZE_CHANGED)).containsExactly(PERIOD_0);
|
||||
assertThat(listener.getEvents(EVENT_RENDERED_FIRST_FRAME)).containsExactly(PERIOD_0);
|
||||
period0 /* audio */, period0 /* video */, period1 /* audio */, period1 /* video */);
|
||||
assertThat(listener.getEvents(EVENT_AUDIO_SESSION_ID)).containsExactly(period0);
|
||||
assertThat(listener.getEvents(EVENT_DROPPED_VIDEO_FRAMES)).containsExactly(period1);
|
||||
assertThat(listener.getEvents(EVENT_VIDEO_SIZE_CHANGED)).containsExactly(period0);
|
||||
assertThat(listener.getEvents(EVENT_RENDERED_FIRST_FRAME)).containsExactly(period0);
|
||||
listener.assertNoMoreEvents();
|
||||
}
|
||||
|
||||
@ -255,47 +245,48 @@ public final class AnalyticsCollectorTest {
|
||||
SINGLE_PERIOD_TIMELINE, /* manifest= */ null, Builder.AUDIO_FORMAT));
|
||||
TestAnalyticsListener listener = runAnalyticsTest(mediaSource);
|
||||
|
||||
populateEventIds(listener.lastReportedTimeline);
|
||||
assertThat(listener.getEvents(EVENT_PLAYER_STATE_CHANGED))
|
||||
.containsExactly(
|
||||
WINDOW_0 /* setPlayWhenReady */,
|
||||
WINDOW_0 /* BUFFERING */,
|
||||
PERIOD_0 /* READY */,
|
||||
PERIOD_1 /* BUFFERING */,
|
||||
PERIOD_1 /* READY */,
|
||||
PERIOD_1 /* ENDED */);
|
||||
period0 /* READY */,
|
||||
period1 /* BUFFERING */,
|
||||
period1 /* READY */,
|
||||
period1 /* ENDED */);
|
||||
assertThat(listener.getEvents(EVENT_TIMELINE_CHANGED)).containsExactly(WINDOW_0);
|
||||
assertThat(listener.getEvents(EVENT_POSITION_DISCONTINUITY)).containsExactly(PERIOD_1);
|
||||
assertThat(listener.getEvents(EVENT_POSITION_DISCONTINUITY)).containsExactly(period1);
|
||||
assertThat(listener.getEvents(EVENT_LOADING_CHANGED))
|
||||
.containsExactly(PERIOD_0, PERIOD_0, PERIOD_0, PERIOD_0);
|
||||
assertThat(listener.getEvents(EVENT_TRACKS_CHANGED)).containsExactly(PERIOD_0, PERIOD_1);
|
||||
.containsExactly(period0, period0, period0, period0);
|
||||
assertThat(listener.getEvents(EVENT_TRACKS_CHANGED)).containsExactly(period0, period1);
|
||||
assertThat(listener.getEvents(EVENT_LOAD_STARTED))
|
||||
.containsExactly(
|
||||
WINDOW_0 /* manifest */,
|
||||
PERIOD_0 /* media */,
|
||||
period0 /* media */,
|
||||
WINDOW_1 /* manifest */,
|
||||
PERIOD_1 /* media */);
|
||||
period1 /* media */);
|
||||
assertThat(listener.getEvents(EVENT_LOAD_COMPLETED))
|
||||
.containsExactly(
|
||||
WINDOW_0 /* manifest */,
|
||||
PERIOD_0 /* media */,
|
||||
period0 /* media */,
|
||||
WINDOW_1 /* manifest */,
|
||||
PERIOD_1 /* media */);
|
||||
period1 /* media */);
|
||||
assertThat(listener.getEvents(EVENT_DOWNSTREAM_FORMAT_CHANGED))
|
||||
.containsExactly(PERIOD_0 /* video */, PERIOD_1 /* audio */);
|
||||
assertThat(listener.getEvents(EVENT_MEDIA_PERIOD_CREATED)).containsExactly(PERIOD_0, PERIOD_1);
|
||||
assertThat(listener.getEvents(EVENT_MEDIA_PERIOD_RELEASED)).containsExactly(PERIOD_0);
|
||||
assertThat(listener.getEvents(EVENT_READING_STARTED)).containsExactly(PERIOD_0, PERIOD_1);
|
||||
.containsExactly(period0 /* video */, period1 /* audio */);
|
||||
assertThat(listener.getEvents(EVENT_MEDIA_PERIOD_CREATED)).containsExactly(period0, period1);
|
||||
assertThat(listener.getEvents(EVENT_MEDIA_PERIOD_RELEASED)).containsExactly(period0);
|
||||
assertThat(listener.getEvents(EVENT_READING_STARTED)).containsExactly(period0, period1);
|
||||
assertThat(listener.getEvents(EVENT_DECODER_ENABLED))
|
||||
.containsExactly(PERIOD_0 /* video */, PERIOD_1 /* audio */);
|
||||
.containsExactly(period0 /* video */, period1 /* audio */);
|
||||
assertThat(listener.getEvents(EVENT_DECODER_INIT))
|
||||
.containsExactly(PERIOD_0 /* video */, PERIOD_1 /* audio */);
|
||||
.containsExactly(period0 /* video */, period1 /* audio */);
|
||||
assertThat(listener.getEvents(EVENT_DECODER_FORMAT_CHANGED))
|
||||
.containsExactly(PERIOD_0 /* video */, PERIOD_1 /* audio */);
|
||||
assertThat(listener.getEvents(EVENT_DECODER_DISABLED)).containsExactly(PERIOD_0);
|
||||
assertThat(listener.getEvents(EVENT_AUDIO_SESSION_ID)).containsExactly(PERIOD_1);
|
||||
assertThat(listener.getEvents(EVENT_DROPPED_VIDEO_FRAMES)).containsExactly(PERIOD_0);
|
||||
assertThat(listener.getEvents(EVENT_VIDEO_SIZE_CHANGED)).containsExactly(PERIOD_0);
|
||||
assertThat(listener.getEvents(EVENT_RENDERED_FIRST_FRAME)).containsExactly(PERIOD_0);
|
||||
.containsExactly(period0 /* video */, period1 /* audio */);
|
||||
assertThat(listener.getEvents(EVENT_DECODER_DISABLED)).containsExactly(period0);
|
||||
assertThat(listener.getEvents(EVENT_AUDIO_SESSION_ID)).containsExactly(period1);
|
||||
assertThat(listener.getEvents(EVENT_DROPPED_VIDEO_FRAMES)).containsExactly(period0);
|
||||
assertThat(listener.getEvents(EVENT_VIDEO_SIZE_CHANGED)).containsExactly(period0);
|
||||
assertThat(listener.getEvents(EVENT_RENDERED_FIRST_FRAME)).containsExactly(period0);
|
||||
listener.assertNoMoreEvents();
|
||||
}
|
||||
|
||||
@ -315,51 +306,52 @@ public final class AnalyticsCollectorTest {
|
||||
.build();
|
||||
TestAnalyticsListener listener = runAnalyticsTest(mediaSource, actionSchedule);
|
||||
|
||||
populateEventIds(listener.lastReportedTimeline);
|
||||
assertThat(listener.getEvents(EVENT_PLAYER_STATE_CHANGED))
|
||||
.containsExactly(
|
||||
WINDOW_0 /* setPlayWhenReady=true */,
|
||||
WINDOW_0 /* BUFFERING */,
|
||||
WINDOW_0 /* setPlayWhenReady=false */,
|
||||
PERIOD_0 /* READY */,
|
||||
PERIOD_1 /* BUFFERING */,
|
||||
PERIOD_1 /* READY */,
|
||||
PERIOD_1 /* setPlayWhenReady=true */,
|
||||
PERIOD_1 /* ENDED */);
|
||||
period0 /* READY */,
|
||||
period1 /* BUFFERING */,
|
||||
period1 /* READY */,
|
||||
period1 /* setPlayWhenReady=true */,
|
||||
period1 /* ENDED */);
|
||||
assertThat(listener.getEvents(EVENT_TIMELINE_CHANGED)).containsExactly(WINDOW_0);
|
||||
assertThat(listener.getEvents(EVENT_POSITION_DISCONTINUITY)).containsExactly(PERIOD_1);
|
||||
assertThat(listener.getEvents(EVENT_SEEK_STARTED)).containsExactly(PERIOD_0);
|
||||
assertThat(listener.getEvents(EVENT_SEEK_PROCESSED)).containsExactly(PERIOD_1);
|
||||
assertThat(listener.getEvents(EVENT_POSITION_DISCONTINUITY)).containsExactly(period1);
|
||||
assertThat(listener.getEvents(EVENT_SEEK_STARTED)).containsExactly(period0);
|
||||
assertThat(listener.getEvents(EVENT_SEEK_PROCESSED)).containsExactly(period1);
|
||||
List<EventWindowAndPeriodId> loadingEvents = listener.getEvents(EVENT_LOADING_CHANGED);
|
||||
assertThat(loadingEvents).hasSize(4);
|
||||
assertThat(loadingEvents).containsAllOf(PERIOD_0, PERIOD_0);
|
||||
assertThat(listener.getEvents(EVENT_TRACKS_CHANGED)).containsExactly(PERIOD_0, PERIOD_1);
|
||||
assertThat(loadingEvents).containsAllOf(period0, period0);
|
||||
assertThat(listener.getEvents(EVENT_TRACKS_CHANGED)).containsExactly(period0, period1);
|
||||
assertThat(listener.getEvents(EVENT_LOAD_STARTED))
|
||||
.containsExactly(
|
||||
WINDOW_0 /* manifest */,
|
||||
PERIOD_0 /* media */,
|
||||
period0 /* media */,
|
||||
WINDOW_1 /* manifest */,
|
||||
PERIOD_1 /* media */);
|
||||
period1 /* media */);
|
||||
assertThat(listener.getEvents(EVENT_LOAD_COMPLETED))
|
||||
.containsExactly(
|
||||
WINDOW_0 /* manifest */,
|
||||
PERIOD_0 /* media */,
|
||||
period0 /* media */,
|
||||
WINDOW_1 /* manifest */,
|
||||
PERIOD_1 /* media */);
|
||||
period1 /* media */);
|
||||
assertThat(listener.getEvents(EVENT_DOWNSTREAM_FORMAT_CHANGED))
|
||||
.containsExactly(PERIOD_0 /* video */, PERIOD_1 /* audio */);
|
||||
assertThat(listener.getEvents(EVENT_MEDIA_PERIOD_CREATED)).containsExactly(PERIOD_0, PERIOD_1);
|
||||
assertThat(listener.getEvents(EVENT_MEDIA_PERIOD_RELEASED)).containsExactly(PERIOD_0);
|
||||
assertThat(listener.getEvents(EVENT_READING_STARTED)).containsExactly(PERIOD_0, PERIOD_1);
|
||||
.containsExactly(period0 /* video */, period1 /* audio */);
|
||||
assertThat(listener.getEvents(EVENT_MEDIA_PERIOD_CREATED)).containsExactly(period0, period1);
|
||||
assertThat(listener.getEvents(EVENT_MEDIA_PERIOD_RELEASED)).containsExactly(period0);
|
||||
assertThat(listener.getEvents(EVENT_READING_STARTED)).containsExactly(period0, period1);
|
||||
assertThat(listener.getEvents(EVENT_DECODER_ENABLED))
|
||||
.containsExactly(PERIOD_0 /* video */, PERIOD_1 /* audio */);
|
||||
.containsExactly(period0 /* video */, period1 /* audio */);
|
||||
assertThat(listener.getEvents(EVENT_DECODER_INIT))
|
||||
.containsExactly(PERIOD_0 /* video */, PERIOD_1 /* audio */);
|
||||
.containsExactly(period0 /* video */, period1 /* audio */);
|
||||
assertThat(listener.getEvents(EVENT_DECODER_FORMAT_CHANGED))
|
||||
.containsExactly(PERIOD_0 /* video */, PERIOD_1 /* audio */);
|
||||
assertThat(listener.getEvents(EVENT_DECODER_DISABLED)).containsExactly(PERIOD_0);
|
||||
assertThat(listener.getEvents(EVENT_AUDIO_SESSION_ID)).containsExactly(PERIOD_1);
|
||||
assertThat(listener.getEvents(EVENT_VIDEO_SIZE_CHANGED)).containsExactly(PERIOD_0);
|
||||
assertThat(listener.getEvents(EVENT_RENDERED_FIRST_FRAME)).containsExactly(PERIOD_0);
|
||||
.containsExactly(period0 /* video */, period1 /* audio */);
|
||||
assertThat(listener.getEvents(EVENT_DECODER_DISABLED)).containsExactly(period0);
|
||||
assertThat(listener.getEvents(EVENT_AUDIO_SESSION_ID)).containsExactly(period1);
|
||||
assertThat(listener.getEvents(EVENT_VIDEO_SIZE_CHANGED)).containsExactly(period0);
|
||||
assertThat(listener.getEvents(EVENT_RENDERED_FIRST_FRAME)).containsExactly(period0);
|
||||
listener.assertNoMoreEvents();
|
||||
}
|
||||
|
||||
@ -386,64 +378,64 @@ public final class AnalyticsCollectorTest {
|
||||
.build();
|
||||
TestAnalyticsListener listener = runAnalyticsTest(mediaSource, actionSchedule);
|
||||
|
||||
populateEventIds(listener.lastReportedTimeline);
|
||||
assertThat(listener.getEvents(EVENT_PLAYER_STATE_CHANGED))
|
||||
.containsExactly(
|
||||
WINDOW_0 /* setPlayWhenReady=true */,
|
||||
WINDOW_0 /* BUFFERING */,
|
||||
WINDOW_0 /* setPlayWhenReady=false */,
|
||||
PERIOD_0 /* READY */,
|
||||
PERIOD_0 /* setPlayWhenReady=true */,
|
||||
PERIOD_0 /* setPlayWhenReady=false */,
|
||||
PERIOD_0 /* BUFFERING */,
|
||||
PERIOD_0 /* READY */,
|
||||
PERIOD_0 /* setPlayWhenReady=true */,
|
||||
PERIOD_1_SEQ_2 /* BUFFERING */,
|
||||
PERIOD_1_SEQ_2 /* READY */,
|
||||
PERIOD_1_SEQ_2 /* ENDED */);
|
||||
period0 /* READY */,
|
||||
period0 /* setPlayWhenReady=true */,
|
||||
period0 /* setPlayWhenReady=false */,
|
||||
period0 /* BUFFERING */,
|
||||
period0 /* READY */,
|
||||
period0 /* setPlayWhenReady=true */,
|
||||
period1Seq2 /* BUFFERING */,
|
||||
period1Seq2 /* READY */,
|
||||
period1Seq2 /* ENDED */);
|
||||
assertThat(listener.getEvents(EVENT_TIMELINE_CHANGED)).containsExactly(WINDOW_0);
|
||||
assertThat(listener.getEvents(EVENT_POSITION_DISCONTINUITY))
|
||||
.containsExactly(PERIOD_0, PERIOD_1_SEQ_2);
|
||||
assertThat(listener.getEvents(EVENT_SEEK_STARTED)).containsExactly(PERIOD_0);
|
||||
assertThat(listener.getEvents(EVENT_SEEK_PROCESSED)).containsExactly(PERIOD_0);
|
||||
.containsExactly(period0, period1Seq2);
|
||||
assertThat(listener.getEvents(EVENT_SEEK_STARTED)).containsExactly(period0);
|
||||
assertThat(listener.getEvents(EVENT_SEEK_PROCESSED)).containsExactly(period0);
|
||||
assertThat(listener.getEvents(EVENT_LOADING_CHANGED))
|
||||
.containsExactly(PERIOD_0, PERIOD_0, PERIOD_0, PERIOD_0, PERIOD_0, PERIOD_0);
|
||||
assertThat(listener.getEvents(EVENT_TRACKS_CHANGED)).containsExactly(PERIOD_0, PERIOD_1_SEQ_2);
|
||||
.containsExactly(period0, period0, period0, period0, period0, period0);
|
||||
assertThat(listener.getEvents(EVENT_TRACKS_CHANGED)).containsExactly(period0, period1Seq2);
|
||||
assertThat(listener.getEvents(EVENT_LOAD_STARTED))
|
||||
.containsExactly(
|
||||
WINDOW_0 /* manifest */,
|
||||
PERIOD_0 /* media */,
|
||||
period0 /* media */,
|
||||
WINDOW_1 /* manifest */,
|
||||
PERIOD_1_SEQ_1 /* media */,
|
||||
PERIOD_1_SEQ_2 /* media */);
|
||||
period1Seq1 /* media */,
|
||||
period1Seq2 /* media */);
|
||||
assertThat(listener.getEvents(EVENT_LOAD_COMPLETED))
|
||||
.containsExactly(
|
||||
WINDOW_0 /* manifest */,
|
||||
PERIOD_0 /* media */,
|
||||
period0 /* media */,
|
||||
WINDOW_1 /* manifest */,
|
||||
PERIOD_1_SEQ_1 /* media */,
|
||||
PERIOD_1_SEQ_2 /* media */);
|
||||
period1Seq1 /* media */,
|
||||
period1Seq2 /* media */);
|
||||
assertThat(listener.getEvents(EVENT_DOWNSTREAM_FORMAT_CHANGED))
|
||||
.containsExactly(PERIOD_0, PERIOD_1_SEQ_1, PERIOD_1_SEQ_2, PERIOD_1_SEQ_2);
|
||||
.containsExactly(period0, period1Seq1, period1Seq2, period1Seq2);
|
||||
assertThat(listener.getEvents(EVENT_MEDIA_PERIOD_CREATED))
|
||||
.containsExactly(PERIOD_0, PERIOD_1_SEQ_1, PERIOD_1_SEQ_2);
|
||||
.containsExactly(period0, period1Seq1, period1Seq2);
|
||||
assertThat(listener.getEvents(EVENT_MEDIA_PERIOD_RELEASED))
|
||||
.containsExactly(PERIOD_0, PERIOD_1_SEQ_1);
|
||||
.containsExactly(period0, period1Seq1);
|
||||
assertThat(listener.getEvents(EVENT_READING_STARTED))
|
||||
.containsExactly(PERIOD_0, PERIOD_1_SEQ_1, PERIOD_1_SEQ_2);
|
||||
.containsExactly(period0, period1Seq1, period1Seq2);
|
||||
assertThat(listener.getEvents(EVENT_DECODER_ENABLED))
|
||||
.containsExactly(PERIOD_0, PERIOD_0, PERIOD_1_SEQ_2);
|
||||
.containsExactly(period0, period0, period1Seq2);
|
||||
assertThat(listener.getEvents(EVENT_DECODER_INIT))
|
||||
.containsExactly(PERIOD_0, PERIOD_1_SEQ_1, PERIOD_1_SEQ_2, PERIOD_1_SEQ_2);
|
||||
.containsExactly(period0, period1Seq1, period1Seq2, period1Seq2);
|
||||
assertThat(listener.getEvents(EVENT_DECODER_FORMAT_CHANGED))
|
||||
.containsExactly(PERIOD_0, PERIOD_1_SEQ_1, PERIOD_1_SEQ_2, PERIOD_1_SEQ_2);
|
||||
assertThat(listener.getEvents(EVENT_DECODER_DISABLED)).containsExactly(PERIOD_0);
|
||||
assertThat(listener.getEvents(EVENT_AUDIO_SESSION_ID)).containsExactly(PERIOD_1_SEQ_2);
|
||||
.containsExactly(period0, period1Seq1, period1Seq2, period1Seq2);
|
||||
assertThat(listener.getEvents(EVENT_DECODER_DISABLED)).containsExactly(period0);
|
||||
assertThat(listener.getEvents(EVENT_AUDIO_SESSION_ID)).containsExactly(period1Seq2);
|
||||
assertThat(listener.getEvents(EVENT_DROPPED_VIDEO_FRAMES))
|
||||
.containsExactly(PERIOD_0, PERIOD_0, PERIOD_1_SEQ_2);
|
||||
assertThat(listener.getEvents(EVENT_VIDEO_SIZE_CHANGED))
|
||||
.containsExactly(PERIOD_0, PERIOD_1_SEQ_2);
|
||||
.containsExactly(period0, period0, period1Seq2);
|
||||
assertThat(listener.getEvents(EVENT_VIDEO_SIZE_CHANGED)).containsExactly(period0, period1Seq2);
|
||||
assertThat(listener.getEvents(EVENT_RENDERED_FIRST_FRAME))
|
||||
.containsExactly(PERIOD_0, PERIOD_1_SEQ_2);
|
||||
.containsExactly(period0, period1Seq2);
|
||||
listener.assertNoMoreEvents();
|
||||
}
|
||||
|
||||
@ -462,54 +454,52 @@ public final class AnalyticsCollectorTest {
|
||||
.build();
|
||||
TestAnalyticsListener listener = runAnalyticsTest(mediaSource1, actionSchedule);
|
||||
|
||||
populateEventIds(SINGLE_PERIOD_TIMELINE);
|
||||
assertThat(listener.getEvents(EVENT_PLAYER_STATE_CHANGED))
|
||||
.containsExactly(
|
||||
WINDOW_0 /* setPlayWhenReady=true */,
|
||||
WINDOW_0 /* BUFFERING */,
|
||||
WINDOW_0 /* setPlayWhenReady=false */,
|
||||
PERIOD_0_SEQ_0 /* READY */,
|
||||
period0Seq0 /* READY */,
|
||||
WINDOW_0 /* BUFFERING */,
|
||||
WINDOW_0 /* setPlayWhenReady=true */,
|
||||
PERIOD_0_SEQ_1 /* READY */,
|
||||
PERIOD_0_SEQ_1 /* ENDED */);
|
||||
period0Seq1 /* READY */,
|
||||
period0Seq1 /* ENDED */);
|
||||
assertThat(listener.getEvents(EVENT_TIMELINE_CHANGED))
|
||||
.containsExactly(WINDOW_0 /* prepared */, WINDOW_0 /* reset */, WINDOW_0 /* prepared */);
|
||||
assertThat(listener.getEvents(EVENT_LOADING_CHANGED))
|
||||
.containsExactly(PERIOD_0_SEQ_0, PERIOD_0_SEQ_0, PERIOD_0_SEQ_1, PERIOD_0_SEQ_1);
|
||||
.containsExactly(period0Seq0, period0Seq0, period0Seq1, period0Seq1);
|
||||
assertThat(listener.getEvents(EVENT_TRACKS_CHANGED))
|
||||
.containsExactly(
|
||||
PERIOD_0_SEQ_0 /* prepared */, WINDOW_0 /* reset */, PERIOD_0_SEQ_1 /* prepared */);
|
||||
period0Seq0 /* prepared */, WINDOW_0 /* reset */, period0Seq1 /* prepared */);
|
||||
assertThat(listener.getEvents(EVENT_LOAD_STARTED))
|
||||
.containsExactly(
|
||||
WINDOW_0 /* manifest */,
|
||||
PERIOD_0_SEQ_0 /* media */,
|
||||
period0Seq0 /* media */,
|
||||
WINDOW_0 /* manifest */,
|
||||
PERIOD_0_SEQ_1 /* media */);
|
||||
period0Seq1 /* media */);
|
||||
assertThat(listener.getEvents(EVENT_LOAD_COMPLETED))
|
||||
.containsExactly(
|
||||
WINDOW_0 /* manifest */,
|
||||
PERIOD_0_SEQ_0 /* media */,
|
||||
period0Seq0 /* media */,
|
||||
WINDOW_0 /* manifest */,
|
||||
PERIOD_0_SEQ_1 /* media */);
|
||||
period0Seq1 /* media */);
|
||||
assertThat(listener.getEvents(EVENT_DOWNSTREAM_FORMAT_CHANGED))
|
||||
.containsExactly(PERIOD_0_SEQ_0, PERIOD_0_SEQ_1);
|
||||
.containsExactly(period0Seq0, period0Seq1);
|
||||
assertThat(listener.getEvents(EVENT_MEDIA_PERIOD_CREATED))
|
||||
.containsExactly(PERIOD_0_SEQ_0, PERIOD_0_SEQ_1);
|
||||
assertThat(listener.getEvents(EVENT_MEDIA_PERIOD_RELEASED)).containsExactly(PERIOD_0_SEQ_0);
|
||||
assertThat(listener.getEvents(EVENT_READING_STARTED))
|
||||
.containsExactly(PERIOD_0_SEQ_0, PERIOD_0_SEQ_1);
|
||||
assertThat(listener.getEvents(EVENT_DECODER_ENABLED))
|
||||
.containsExactly(PERIOD_0_SEQ_0, PERIOD_0_SEQ_1);
|
||||
assertThat(listener.getEvents(EVENT_DECODER_INIT))
|
||||
.containsExactly(PERIOD_0_SEQ_0, PERIOD_0_SEQ_1);
|
||||
.containsExactly(period0Seq0, period0Seq1);
|
||||
assertThat(listener.getEvents(EVENT_MEDIA_PERIOD_RELEASED)).containsExactly(period0Seq0);
|
||||
assertThat(listener.getEvents(EVENT_READING_STARTED)).containsExactly(period0Seq0, period0Seq1);
|
||||
assertThat(listener.getEvents(EVENT_DECODER_ENABLED)).containsExactly(period0Seq0, period0Seq1);
|
||||
assertThat(listener.getEvents(EVENT_DECODER_INIT)).containsExactly(period0Seq0, period0Seq1);
|
||||
assertThat(listener.getEvents(EVENT_DECODER_FORMAT_CHANGED))
|
||||
.containsExactly(PERIOD_0_SEQ_0, PERIOD_0_SEQ_1);
|
||||
assertThat(listener.getEvents(EVENT_DECODER_DISABLED)).containsExactly(PERIOD_0_SEQ_0);
|
||||
assertThat(listener.getEvents(EVENT_DROPPED_VIDEO_FRAMES)).containsExactly(PERIOD_0_SEQ_1);
|
||||
.containsExactly(period0Seq0, period0Seq1);
|
||||
assertThat(listener.getEvents(EVENT_DECODER_DISABLED)).containsExactly(period0Seq0);
|
||||
assertThat(listener.getEvents(EVENT_DROPPED_VIDEO_FRAMES)).containsExactly(period0Seq1);
|
||||
assertThat(listener.getEvents(EVENT_VIDEO_SIZE_CHANGED))
|
||||
.containsExactly(PERIOD_0_SEQ_0, PERIOD_0_SEQ_1);
|
||||
.containsExactly(period0Seq0, period0Seq1);
|
||||
assertThat(listener.getEvents(EVENT_RENDERED_FIRST_FRAME))
|
||||
.containsExactly(PERIOD_0_SEQ_0, PERIOD_0_SEQ_1);
|
||||
.containsExactly(period0Seq0, period0Seq1);
|
||||
listener.assertNoMoreEvents();
|
||||
}
|
||||
|
||||
@ -527,55 +517,51 @@ public final class AnalyticsCollectorTest {
|
||||
.build();
|
||||
TestAnalyticsListener listener = runAnalyticsTest(mediaSource, actionSchedule);
|
||||
|
||||
populateEventIds(SINGLE_PERIOD_TIMELINE);
|
||||
assertThat(listener.getEvents(EVENT_PLAYER_STATE_CHANGED))
|
||||
.containsExactly(
|
||||
WINDOW_0 /* setPlayWhenReady=true */,
|
||||
WINDOW_0 /* BUFFERING */,
|
||||
PERIOD_0_SEQ_0 /* READY */,
|
||||
period0Seq0 /* READY */,
|
||||
WINDOW_0 /* IDLE */,
|
||||
WINDOW_0 /* BUFFERING */,
|
||||
PERIOD_0_SEQ_0 /* READY */,
|
||||
PERIOD_0_SEQ_0 /* ENDED */);
|
||||
// assertThat(listener.getEvents(EVENT_PLAYER_STATE_CHANGED)).doesNotContain(PERIOD_0_SEQ_1);
|
||||
period0Seq0 /* READY */,
|
||||
period0Seq0 /* ENDED */);
|
||||
assertThat(listener.getEvents(EVENT_TIMELINE_CHANGED))
|
||||
.containsExactly(WINDOW_0 /* prepared */, WINDOW_0 /* prepared */);
|
||||
assertThat(listener.getEvents(EVENT_LOADING_CHANGED))
|
||||
.containsExactly(PERIOD_0_SEQ_0, PERIOD_0_SEQ_0, PERIOD_0_SEQ_0, PERIOD_0_SEQ_0);
|
||||
.containsExactly(period0Seq0, period0Seq0, period0Seq0, period0Seq0);
|
||||
assertThat(listener.getEvents(EVENT_PLAYER_ERROR)).containsExactly(WINDOW_0);
|
||||
assertThat(listener.getEvents(EVENT_TRACKS_CHANGED))
|
||||
.containsExactly(PERIOD_0_SEQ_0, PERIOD_0_SEQ_0);
|
||||
assertThat(listener.getEvents(EVENT_TRACKS_CHANGED)).containsExactly(period0Seq0, period0Seq0);
|
||||
assertThat(listener.getEvents(EVENT_LOAD_STARTED))
|
||||
.containsExactly(
|
||||
WINDOW_0 /* manifest */,
|
||||
PERIOD_0_SEQ_0 /* media */,
|
||||
period0Seq0 /* media */,
|
||||
WINDOW_0 /* manifest */,
|
||||
PERIOD_0_SEQ_0 /* media */);
|
||||
period0Seq0 /* media */);
|
||||
assertThat(listener.getEvents(EVENT_LOAD_COMPLETED))
|
||||
.containsExactly(
|
||||
WINDOW_0 /* manifest */,
|
||||
PERIOD_0_SEQ_0 /* media */,
|
||||
period0Seq0 /* media */,
|
||||
WINDOW_0 /* manifest */,
|
||||
PERIOD_0_SEQ_0 /* media */);
|
||||
period0Seq0 /* media */);
|
||||
assertThat(listener.getEvents(EVENT_DOWNSTREAM_FORMAT_CHANGED))
|
||||
.containsExactly(PERIOD_0_SEQ_0, PERIOD_0_SEQ_0);
|
||||
.containsExactly(period0Seq0, period0Seq0);
|
||||
assertThat(listener.getEvents(EVENT_MEDIA_PERIOD_CREATED))
|
||||
.containsExactly(PERIOD_0_SEQ_0, PERIOD_0_SEQ_0);
|
||||
assertThat(listener.getEvents(EVENT_MEDIA_PERIOD_RELEASED)).containsExactly(PERIOD_0_SEQ_0);
|
||||
assertThat(listener.getEvents(EVENT_READING_STARTED))
|
||||
.containsExactly(PERIOD_0_SEQ_0, PERIOD_0_SEQ_0);
|
||||
assertThat(listener.getEvents(EVENT_DECODER_ENABLED))
|
||||
.containsExactly(PERIOD_0_SEQ_0, PERIOD_0_SEQ_0);
|
||||
assertThat(listener.getEvents(EVENT_DECODER_INIT))
|
||||
.containsExactly(PERIOD_0_SEQ_0, PERIOD_0_SEQ_0);
|
||||
.containsExactly(period0Seq0, period0Seq0);
|
||||
assertThat(listener.getEvents(EVENT_MEDIA_PERIOD_RELEASED)).containsExactly(period0Seq0);
|
||||
assertThat(listener.getEvents(EVENT_READING_STARTED)).containsExactly(period0Seq0, period0Seq0);
|
||||
assertThat(listener.getEvents(EVENT_DECODER_ENABLED)).containsExactly(period0Seq0, period0Seq0);
|
||||
assertThat(listener.getEvents(EVENT_DECODER_INIT)).containsExactly(period0Seq0, period0Seq0);
|
||||
assertThat(listener.getEvents(EVENT_DECODER_FORMAT_CHANGED))
|
||||
.containsExactly(PERIOD_0_SEQ_0, PERIOD_0_SEQ_0);
|
||||
assertThat(listener.getEvents(EVENT_DECODER_DISABLED)).containsExactly(PERIOD_0_SEQ_0);
|
||||
.containsExactly(period0Seq0, period0Seq0);
|
||||
assertThat(listener.getEvents(EVENT_DECODER_DISABLED)).containsExactly(period0Seq0);
|
||||
assertThat(listener.getEvents(EVENT_DROPPED_VIDEO_FRAMES))
|
||||
.containsExactly(PERIOD_0_SEQ_0, PERIOD_0_SEQ_0);
|
||||
.containsExactly(period0Seq0, period0Seq0);
|
||||
assertThat(listener.getEvents(EVENT_VIDEO_SIZE_CHANGED))
|
||||
.containsExactly(PERIOD_0_SEQ_0, PERIOD_0_SEQ_0);
|
||||
.containsExactly(period0Seq0, period0Seq0);
|
||||
assertThat(listener.getEvents(EVENT_RENDERED_FIRST_FRAME))
|
||||
.containsExactly(PERIOD_0_SEQ_0, PERIOD_0_SEQ_0);
|
||||
.containsExactly(period0Seq0, period0Seq0);
|
||||
listener.assertNoMoreEvents();
|
||||
}
|
||||
|
||||
@ -602,45 +588,50 @@ public final class AnalyticsCollectorTest {
|
||||
.build();
|
||||
TestAnalyticsListener listener = runAnalyticsTest(concatenatedMediaSource, actionSchedule);
|
||||
|
||||
populateEventIds(listener.lastReportedTimeline);
|
||||
assertThat(listener.getEvents(EVENT_PLAYER_STATE_CHANGED))
|
||||
.containsExactly(
|
||||
WINDOW_0 /* setPlayWhenReady=true */,
|
||||
WINDOW_0 /* BUFFERING */,
|
||||
WINDOW_0 /* setPlayWhenReady=false */,
|
||||
PERIOD_0_SEQ_0 /* READY */,
|
||||
PERIOD_0_SEQ_0 /* setPlayWhenReady=true */,
|
||||
PERIOD_0_SEQ_0 /* setPlayWhenReady=false */,
|
||||
PERIOD_1_SEQ_0 /* setPlayWhenReady=true */,
|
||||
PERIOD_1_SEQ_0 /* BUFFERING */,
|
||||
PERIOD_1_SEQ_0 /* ENDED */);
|
||||
assertThat(listener.getEvents(EVENT_TIMELINE_CHANGED))
|
||||
.containsExactly(WINDOW_0, PERIOD_1_SEQ_0);
|
||||
window0Period1Seq0 /* READY */,
|
||||
window0Period1Seq0 /* setPlayWhenReady=true */,
|
||||
window0Period1Seq0 /* setPlayWhenReady=false */,
|
||||
period1Seq0 /* setPlayWhenReady=true */,
|
||||
period1Seq0 /* BUFFERING */,
|
||||
period1Seq0 /* ENDED */);
|
||||
assertThat(listener.getEvents(EVENT_TIMELINE_CHANGED)).containsExactly(WINDOW_0, period1Seq0);
|
||||
assertThat(listener.getEvents(EVENT_LOADING_CHANGED))
|
||||
.containsExactly(PERIOD_0_SEQ_0, PERIOD_0_SEQ_0, PERIOD_0_SEQ_0, PERIOD_0_SEQ_0);
|
||||
assertThat(listener.getEvents(EVENT_TRACKS_CHANGED)).containsExactly(PERIOD_0_SEQ_0);
|
||||
.containsExactly(
|
||||
window0Period1Seq0, window0Period1Seq0, window0Period1Seq0, window0Period1Seq0);
|
||||
assertThat(listener.getEvents(EVENT_TRACKS_CHANGED)).containsExactly(window0Period1Seq0);
|
||||
assertThat(listener.getEvents(EVENT_LOAD_STARTED))
|
||||
.containsExactly(
|
||||
WINDOW_0 /* manifest */, PERIOD_0_SEQ_0 /* media */, PERIOD_1_SEQ_1 /* media */);
|
||||
WINDOW_0 /* manifest */,
|
||||
window0Period1Seq0 /* media */,
|
||||
window1Period0Seq1 /* media */);
|
||||
assertThat(listener.getEvents(EVENT_LOAD_COMPLETED))
|
||||
.containsExactly(
|
||||
WINDOW_0 /* manifest */, PERIOD_0_SEQ_0 /* media */, PERIOD_1_SEQ_1 /* media */);
|
||||
WINDOW_0 /* manifest */,
|
||||
window0Period1Seq0 /* media */,
|
||||
window1Period0Seq1 /* media */);
|
||||
assertThat(listener.getEvents(EVENT_DOWNSTREAM_FORMAT_CHANGED))
|
||||
.containsExactly(PERIOD_0_SEQ_0, PERIOD_1_SEQ_1);
|
||||
.containsExactly(window0Period1Seq0, window1Period0Seq1);
|
||||
assertThat(listener.getEvents(EVENT_MEDIA_PERIOD_CREATED))
|
||||
.containsExactly(PERIOD_0_SEQ_0, PERIOD_1_SEQ_1);
|
||||
assertThat(listener.getEvents(EVENT_MEDIA_PERIOD_RELEASED)).containsExactly(PERIOD_0_SEQ_1);
|
||||
.containsExactly(window0Period1Seq0, window1Period0Seq1);
|
||||
assertThat(listener.getEvents(EVENT_MEDIA_PERIOD_RELEASED)).containsExactly(period0Seq1);
|
||||
assertThat(listener.getEvents(EVENT_READING_STARTED))
|
||||
.containsExactly(PERIOD_0_SEQ_0, PERIOD_1_SEQ_1);
|
||||
.containsExactly(window0Period1Seq0, window1Period0Seq1);
|
||||
assertThat(listener.getEvents(EVENT_DECODER_ENABLED))
|
||||
.containsExactly(PERIOD_0_SEQ_0, PERIOD_0_SEQ_0);
|
||||
.containsExactly(window0Period1Seq0, window0Period1Seq0);
|
||||
assertThat(listener.getEvents(EVENT_DECODER_INIT))
|
||||
.containsExactly(PERIOD_0_SEQ_0, PERIOD_1_SEQ_1);
|
||||
.containsExactly(window0Period1Seq0, window1Period0Seq1);
|
||||
assertThat(listener.getEvents(EVENT_DECODER_FORMAT_CHANGED))
|
||||
.containsExactly(PERIOD_0_SEQ_0, PERIOD_1_SEQ_1);
|
||||
assertThat(listener.getEvents(EVENT_DECODER_DISABLED)).containsExactly(PERIOD_0_SEQ_0);
|
||||
assertThat(listener.getEvents(EVENT_DROPPED_VIDEO_FRAMES)).containsExactly(PERIOD_0_SEQ_0);
|
||||
assertThat(listener.getEvents(EVENT_VIDEO_SIZE_CHANGED)).containsExactly(PERIOD_0_SEQ_0);
|
||||
assertThat(listener.getEvents(EVENT_RENDERED_FIRST_FRAME)).containsExactly(PERIOD_0_SEQ_0);
|
||||
.containsExactly(window0Period1Seq0, window1Period0Seq1);
|
||||
assertThat(listener.getEvents(EVENT_DECODER_DISABLED)).containsExactly(window0Period1Seq0);
|
||||
assertThat(listener.getEvents(EVENT_DROPPED_VIDEO_FRAMES)).containsExactly(window0Period1Seq0);
|
||||
assertThat(listener.getEvents(EVENT_VIDEO_SIZE_CHANGED)).containsExactly(window0Period1Seq0);
|
||||
assertThat(listener.getEvents(EVENT_RENDERED_FIRST_FRAME)).containsExactly(window0Period1Seq0);
|
||||
listener.assertNoMoreEvents();
|
||||
}
|
||||
|
||||
@ -663,8 +654,51 @@ public final class AnalyticsCollectorTest {
|
||||
.build();
|
||||
TestAnalyticsListener listener = runAnalyticsTest(mediaSource, actionSchedule);
|
||||
|
||||
assertThat(listener.getEvents(EVENT_SEEK_STARTED)).containsExactly(PERIOD_0);
|
||||
assertThat(listener.getEvents(EVENT_SEEK_PROCESSED)).containsExactly(PERIOD_0);
|
||||
populateEventIds(SINGLE_PERIOD_TIMELINE);
|
||||
assertThat(listener.getEvents(EVENT_SEEK_STARTED)).containsExactly(period0);
|
||||
assertThat(listener.getEvents(EVENT_SEEK_PROCESSED)).containsExactly(period0);
|
||||
}
|
||||
|
||||
private void populateEventIds(Timeline timeline) {
|
||||
period0 =
|
||||
new EventWindowAndPeriodId(
|
||||
/* windowIndex= */ 0,
|
||||
new MediaPeriodId(
|
||||
timeline.getUidOfPeriod(/* periodIndex= */ 0), /* windowSequenceNumber= */ 0));
|
||||
period0Seq0 = period0;
|
||||
period0Seq1 =
|
||||
new EventWindowAndPeriodId(
|
||||
/* windowIndex= */ 0,
|
||||
new MediaPeriodId(
|
||||
timeline.getUidOfPeriod(/* periodIndex= */ 0), /* windowSequenceNumber= */ 1));
|
||||
window1Period0Seq1 =
|
||||
new EventWindowAndPeriodId(
|
||||
/* windowIndex= */ 1,
|
||||
new MediaPeriodId(
|
||||
timeline.getUidOfPeriod(/* periodIndex= */ 0), /* windowSequenceNumber= */ 1));
|
||||
if (timeline.getPeriodCount() > 1) {
|
||||
period1 =
|
||||
new EventWindowAndPeriodId(
|
||||
/* windowIndex= */ 1,
|
||||
new MediaPeriodId(
|
||||
timeline.getUidOfPeriod(/* periodIndex= */ 1), /* windowSequenceNumber= */ 1));
|
||||
period1Seq1 = period1;
|
||||
period1Seq0 =
|
||||
new EventWindowAndPeriodId(
|
||||
/* windowIndex= */ 1,
|
||||
new MediaPeriodId(
|
||||
timeline.getUidOfPeriod(/* periodIndex= */ 1), /* windowSequenceNumber= */ 0));
|
||||
period1Seq2 =
|
||||
new EventWindowAndPeriodId(
|
||||
/* windowIndex= */ 1,
|
||||
new MediaPeriodId(
|
||||
timeline.getUidOfPeriod(/* periodIndex= */ 1), /* windowSequenceNumber= */ 2));
|
||||
window0Period1Seq0 =
|
||||
new EventWindowAndPeriodId(
|
||||
/* windowIndex= */ 0,
|
||||
new MediaPeriodId(
|
||||
timeline.getUidOfPeriod(/* periodIndex= */ 1), /* windowSequenceNumber= */ 0));
|
||||
}
|
||||
}
|
||||
|
||||
private static TestAnalyticsListener runAnalyticsTest(MediaSource mediaSource) throws Exception {
|
||||
@ -834,7 +868,7 @@ public final class AnalyticsCollectorTest {
|
||||
+ "window="
|
||||
+ windowIndex
|
||||
+ ", period="
|
||||
+ mediaPeriodId.periodIndex
|
||||
+ mediaPeriodId.periodUid
|
||||
+ ", sequence="
|
||||
+ mediaPeriodId.windowSequenceNumber
|
||||
+ '}'
|
||||
@ -849,10 +883,13 @@ public final class AnalyticsCollectorTest {
|
||||
|
||||
private static final class TestAnalyticsListener implements AnalyticsListener {
|
||||
|
||||
public Timeline lastReportedTimeline;
|
||||
|
||||
private final ArrayList<ReportedEvent> reportedEvents;
|
||||
|
||||
public TestAnalyticsListener() {
|
||||
reportedEvents = new ArrayList<>();
|
||||
lastReportedTimeline = Timeline.EMPTY;
|
||||
}
|
||||
|
||||
public List<EventWindowAndPeriodId> getEvents(int eventType) {
|
||||
@ -880,6 +917,7 @@ public final class AnalyticsCollectorTest {
|
||||
|
||||
@Override
|
||||
public void onTimelineChanged(EventTime eventTime, int reason) {
|
||||
lastReportedTimeline = eventTime.timeline;
|
||||
reportedEvents.add(new ReportedEvent(EVENT_TIMELINE_CHANGED, eventTime));
|
||||
}
|
||||
|
||||
|
@ -469,11 +469,11 @@ public final class ClippingMediaSourceTest {
|
||||
private static MediaLoadData getClippingMediaSourceMediaLoadData(
|
||||
long clippingStartUs, long clippingEndUs, final long eventStartUs, final long eventEndUs)
|
||||
throws IOException {
|
||||
Timeline timeline =
|
||||
new SinglePeriodTimeline(
|
||||
TEST_PERIOD_DURATION_US, /* isSeekable= */ true, /* isDynamic= */ false);
|
||||
FakeMediaSource fakeMediaSource =
|
||||
new FakeMediaSource(
|
||||
new SinglePeriodTimeline(
|
||||
TEST_PERIOD_DURATION_US, /* isSeekable= */ true, /* isDynamic= */ false),
|
||||
/* manifest= */ null) {
|
||||
new FakeMediaSource(timeline, /* manifest= */ null) {
|
||||
@Override
|
||||
protected FakeMediaPeriod createFakeMediaPeriod(
|
||||
MediaPeriodId id,
|
||||
@ -516,7 +516,8 @@ public final class ClippingMediaSourceTest {
|
||||
testRunner.prepareSource();
|
||||
// Create period to send the test event configured above.
|
||||
testRunner.createPeriod(
|
||||
new MediaPeriodId(/* periodIndex= */ 0, /* windowSequenceNumber= */ 0));
|
||||
new MediaPeriodId(
|
||||
timeline.getUidOfPeriod(/* periodIndex= */ 0), /* windowSequenceNumber= */ 0));
|
||||
assertThat(reportedMediaLoadData[0]).isNotNull();
|
||||
} finally {
|
||||
testRunner.release();
|
||||
@ -580,7 +581,9 @@ public final class ClippingMediaSourceTest {
|
||||
clippedTimelines[0] = testRunner.prepareSource();
|
||||
MediaPeriod mediaPeriod =
|
||||
testRunner.createPeriod(
|
||||
new MediaPeriodId(/* periodIndex= */ 0, /* windowSequenceNumber= */ 0));
|
||||
new MediaPeriodId(
|
||||
clippedTimelines[0].getUidOfPeriod(/* periodIndex= */ 0),
|
||||
/* windowSequenceNumber= */ 0));
|
||||
for (int i = 0; i < additionalTimelines.length; i++) {
|
||||
fakeMediaSource.setNewSourceInfo(additionalTimelines[i], /* newManifest= */ null);
|
||||
clippedTimelines[i + 1] = testRunner.assertTimelineChangeBlocking();
|
||||
|
@ -274,14 +274,16 @@ public final class ConcatenatingMediaSourceTest {
|
||||
// called yet.
|
||||
MediaPeriod lazyPeriod =
|
||||
testRunner.createPeriod(
|
||||
new MediaPeriodId(/* periodIndex= */ 0, /* windowSequenceNumber= */ 0));
|
||||
new MediaPeriodId(
|
||||
timeline.getUidOfPeriod(/* periodIndex= */ 0), /* windowSequenceNumber= */ 0));
|
||||
CountDownLatch preparedCondition = testRunner.preparePeriod(lazyPeriod, 0);
|
||||
assertThat(preparedCondition.getCount()).isEqualTo(1);
|
||||
|
||||
// Assert that a second period can also be created and released without problems.
|
||||
MediaPeriod secondLazyPeriod =
|
||||
testRunner.createPeriod(
|
||||
new MediaPeriodId(/* periodIndex= */ 0, /* windowSequenceNumber= */ 0));
|
||||
new MediaPeriodId(
|
||||
timeline.getUidOfPeriod(/* periodIndex= */ 0), /* windowSequenceNumber= */ 0));
|
||||
testRunner.releasePeriod(secondLazyPeriod);
|
||||
|
||||
// Trigger source info refresh for lazy media source. Assert that now all information is
|
||||
@ -605,23 +607,27 @@ public final class ConcatenatingMediaSourceTest {
|
||||
|
||||
// Create all periods and assert period creation of child media sources has been called.
|
||||
testRunner.assertPrepareAndReleaseAllPeriods();
|
||||
Object timelineContentOnlyPeriodUid0 = timelineContentOnly.getUidOfPeriod(/* periodIndex= */ 0);
|
||||
Object timelineContentOnlyPeriodUid1 = timelineContentOnly.getUidOfPeriod(/* periodIndex= */ 1);
|
||||
Object timelineWithAdsPeriodUid0 = timelineWithAds.getUidOfPeriod(/* periodIndex= */ 0);
|
||||
Object timelineWithAdsPeriodUid1 = timelineWithAds.getUidOfPeriod(/* periodIndex= */ 1);
|
||||
mediaSourceContentOnly.assertMediaPeriodCreated(
|
||||
new MediaPeriodId(/* periodIndex= */ 0, /* windowSequenceNumber= */ 0));
|
||||
new MediaPeriodId(timelineContentOnlyPeriodUid0, /* windowSequenceNumber= */ 0));
|
||||
mediaSourceContentOnly.assertMediaPeriodCreated(
|
||||
new MediaPeriodId(/* periodIndex= */ 1, /* windowSequenceNumber= */ 0));
|
||||
new MediaPeriodId(timelineContentOnlyPeriodUid1, /* windowSequenceNumber= */ 0));
|
||||
mediaSourceWithAds.assertMediaPeriodCreated(
|
||||
new MediaPeriodId(/* periodIndex= */ 0, /* windowSequenceNumber= */ 1));
|
||||
new MediaPeriodId(timelineWithAdsPeriodUid0, /* windowSequenceNumber= */ 1));
|
||||
mediaSourceWithAds.assertMediaPeriodCreated(
|
||||
new MediaPeriodId(/* periodIndex= */ 1, /* windowSequenceNumber= */ 1));
|
||||
new MediaPeriodId(timelineWithAdsPeriodUid1, /* windowSequenceNumber= */ 1));
|
||||
mediaSourceWithAds.assertMediaPeriodCreated(
|
||||
new MediaPeriodId(
|
||||
/* periodIndex= */ 0,
|
||||
timelineWithAdsPeriodUid0,
|
||||
/* adGroupIndex= */ 0,
|
||||
/* adIndexInAdGroup= */ 0,
|
||||
/* windowSequenceNumber= */ 1));
|
||||
mediaSourceWithAds.assertMediaPeriodCreated(
|
||||
new MediaPeriodId(
|
||||
/* periodIndex= */ 1,
|
||||
timelineWithAdsPeriodUid1,
|
||||
/* adGroupIndex= */ 0,
|
||||
/* adIndexInAdGroup= */ 0,
|
||||
/* windowSequenceNumber= */ 1));
|
||||
@ -721,10 +727,11 @@ public final class ConcatenatingMediaSourceTest {
|
||||
public void testRemoveChildSourceWithActiveMediaPeriod() throws IOException {
|
||||
FakeMediaSource childSource = createFakeMediaSource();
|
||||
mediaSource.addMediaSource(childSource);
|
||||
testRunner.prepareSource();
|
||||
Timeline timeline = testRunner.prepareSource();
|
||||
MediaPeriod mediaPeriod =
|
||||
testRunner.createPeriod(
|
||||
new MediaPeriodId(/* periodIndex= */ 0, /* windowSequenceNumber= */ 0));
|
||||
new MediaPeriodId(
|
||||
timeline.getUidOfPeriod(/* periodIndex= */ 0), /* windowSequenceNumber= */ 0));
|
||||
mediaSource.removeMediaSource(/* index= */ 0);
|
||||
testRunner.assertTimelineChangeBlocking();
|
||||
testRunner.releasePeriod(mediaPeriod);
|
||||
@ -734,8 +741,8 @@ public final class ConcatenatingMediaSourceTest {
|
||||
|
||||
@Test
|
||||
public void testDuplicateMediaSources() throws IOException, InterruptedException {
|
||||
FakeMediaSource childSource =
|
||||
new FakeMediaSource(new FakeTimeline(/* windowCount= */ 2), /* manifest= */ null);
|
||||
Timeline childTimeline = new FakeTimeline(/* windowCount= */ 2);
|
||||
FakeMediaSource childSource = new FakeMediaSource(childTimeline, /* manifest= */ null);
|
||||
|
||||
mediaSource.addMediaSource(childSource);
|
||||
mediaSource.addMediaSource(childSource);
|
||||
@ -745,16 +752,18 @@ public final class ConcatenatingMediaSourceTest {
|
||||
|
||||
TimelineAsserts.assertPeriodCounts(timeline, 1, 1, 1, 1, 1, 1, 1, 1);
|
||||
testRunner.assertPrepareAndReleaseAllPeriods();
|
||||
Object childPeriodUid0 = childTimeline.getUidOfPeriod(/* periodIndex= */ 0);
|
||||
Object childPeriodUid1 = childTimeline.getUidOfPeriod(/* periodIndex= */ 1);
|
||||
assertThat(childSource.getCreatedMediaPeriods())
|
||||
.containsAllOf(
|
||||
new MediaPeriodId(/* periodIndex= */ 0, /* windowSequenceNumber= */ 0),
|
||||
new MediaPeriodId(/* periodIndex= */ 0, /* windowSequenceNumber= */ 2),
|
||||
new MediaPeriodId(/* periodIndex= */ 0, /* windowSequenceNumber= */ 4),
|
||||
new MediaPeriodId(/* periodIndex= */ 0, /* windowSequenceNumber= */ 6),
|
||||
new MediaPeriodId(/* periodIndex= */ 1, /* windowSequenceNumber= */ 1),
|
||||
new MediaPeriodId(/* periodIndex= */ 1, /* windowSequenceNumber= */ 3),
|
||||
new MediaPeriodId(/* periodIndex= */ 1, /* windowSequenceNumber= */ 5),
|
||||
new MediaPeriodId(/* periodIndex= */ 1, /* windowSequenceNumber= */ 7));
|
||||
new MediaPeriodId(childPeriodUid0, /* windowSequenceNumber= */ 0),
|
||||
new MediaPeriodId(childPeriodUid0, /* windowSequenceNumber= */ 2),
|
||||
new MediaPeriodId(childPeriodUid0, /* windowSequenceNumber= */ 4),
|
||||
new MediaPeriodId(childPeriodUid0, /* windowSequenceNumber= */ 6),
|
||||
new MediaPeriodId(childPeriodUid1, /* windowSequenceNumber= */ 1),
|
||||
new MediaPeriodId(childPeriodUid1, /* windowSequenceNumber= */ 3),
|
||||
new MediaPeriodId(childPeriodUid1, /* windowSequenceNumber= */ 5),
|
||||
new MediaPeriodId(childPeriodUid1, /* windowSequenceNumber= */ 7));
|
||||
// Assert that only one manifest load is reported because the source is reused.
|
||||
testRunner.assertCompletedManifestLoads(/* windowIndices= */ 0);
|
||||
assertCompletedAllMediaPeriodLoads(timeline);
|
||||
@ -765,8 +774,8 @@ public final class ConcatenatingMediaSourceTest {
|
||||
|
||||
@Test
|
||||
public void testDuplicateNestedMediaSources() throws IOException, InterruptedException {
|
||||
FakeMediaSource childSource =
|
||||
new FakeMediaSource(new FakeTimeline(/* windowCount= */ 1), /* manifest= */ null);
|
||||
Timeline childTimeline = new FakeTimeline(/* windowCount= */ 1);
|
||||
FakeMediaSource childSource = new FakeMediaSource(childTimeline, /* manifest= */ null);
|
||||
ConcatenatingMediaSource nestedConcatenation = new ConcatenatingMediaSource();
|
||||
|
||||
testRunner.prepareSource();
|
||||
@ -780,13 +789,14 @@ public final class ConcatenatingMediaSourceTest {
|
||||
|
||||
TimelineAsserts.assertPeriodCounts(timeline, 1, 1, 1, 1, 1);
|
||||
testRunner.assertPrepareAndReleaseAllPeriods();
|
||||
Object childPeriodUid = childTimeline.getUidOfPeriod(/* periodIndex= */ 0);
|
||||
assertThat(childSource.getCreatedMediaPeriods())
|
||||
.containsAllOf(
|
||||
new MediaPeriodId(/* periodIndex= */ 0, /* windowSequenceNumber= */ 0),
|
||||
new MediaPeriodId(/* periodIndex= */ 0, /* windowSequenceNumber= */ 1),
|
||||
new MediaPeriodId(/* periodIndex= */ 0, /* windowSequenceNumber= */ 2),
|
||||
new MediaPeriodId(/* periodIndex= */ 0, /* windowSequenceNumber= */ 3),
|
||||
new MediaPeriodId(/* periodIndex= */ 0, /* windowSequenceNumber= */ 4));
|
||||
new MediaPeriodId(childPeriodUid, /* windowSequenceNumber= */ 0),
|
||||
new MediaPeriodId(childPeriodUid, /* windowSequenceNumber= */ 1),
|
||||
new MediaPeriodId(childPeriodUid, /* windowSequenceNumber= */ 2),
|
||||
new MediaPeriodId(childPeriodUid, /* windowSequenceNumber= */ 3),
|
||||
new MediaPeriodId(childPeriodUid, /* windowSequenceNumber= */ 4));
|
||||
// Assert that only one manifest load is needed because the source is reused.
|
||||
testRunner.assertCompletedManifestLoads(/* windowIndices= */ 0);
|
||||
assertCompletedAllMediaPeriodLoads(timeline);
|
||||
@ -844,16 +854,18 @@ public final class ConcatenatingMediaSourceTest {
|
||||
ConcatenatingMediaSource childSource = new ConcatenatingMediaSource(nestedChildSources);
|
||||
mediaSource.addMediaSource(childSource);
|
||||
|
||||
testRunner.prepareSource();
|
||||
Timeline timeline = testRunner.prepareSource();
|
||||
MediaPeriod mediaPeriod =
|
||||
testRunner.createPeriod(
|
||||
new MediaPeriodId(/* periodIndex= */ 1, /* windowSequenceNumber= */ 0));
|
||||
new MediaPeriodId(
|
||||
timeline.getUidOfPeriod(/* periodIndex= */ 1), /* windowSequenceNumber= */ 0));
|
||||
childSource.moveMediaSource(/* currentIndex= */ 0, /* newIndex= */ 1);
|
||||
testRunner.assertTimelineChangeBlocking();
|
||||
timeline = testRunner.assertTimelineChangeBlocking();
|
||||
testRunner.preparePeriod(mediaPeriod, /* positionUs= */ 0);
|
||||
|
||||
testRunner.assertCompletedMediaPeriodLoads(
|
||||
new MediaPeriodId(/* periodIndex= */ 0, /* windowSequenceNumber= */ 0));
|
||||
new MediaPeriodId(
|
||||
timeline.getUidOfPeriod(/* periodIndex= */ 0), /* windowSequenceNumber= */ 0));
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -882,8 +894,10 @@ public final class ConcatenatingMediaSourceTest {
|
||||
new DefaultShuffleOrder(0),
|
||||
childSources);
|
||||
testRunner = new MediaSourceTestRunner(mediaSource, /* allocator= */ null);
|
||||
testRunner.prepareSource();
|
||||
testRunner.createPeriod(new MediaPeriodId(/* periodIndex= */ 0, /* windowSequenceNumber= */ 0));
|
||||
Timeline timeline = testRunner.prepareSource();
|
||||
testRunner.createPeriod(
|
||||
new MediaPeriodId(
|
||||
timeline.getUidOfPeriod(/* periodIndex= */ 0), /* windowSequenceNumber= */ 0));
|
||||
|
||||
assertThat(childSources[0].isPrepared()).isTrue();
|
||||
assertThat(childSources[1].isPrepared()).isFalse();
|
||||
@ -899,13 +913,16 @@ public final class ConcatenatingMediaSourceTest {
|
||||
new DefaultShuffleOrder(0),
|
||||
childSources);
|
||||
testRunner = new MediaSourceTestRunner(mediaSource, /* allocator= */ null);
|
||||
testRunner.prepareSource();
|
||||
Timeline timeline = testRunner.prepareSource();
|
||||
|
||||
// The lazy preparation must only be triggered once, even if we create multiple periods from
|
||||
// the media source. FakeMediaSource.prepareSource asserts that it's not called twice, so
|
||||
// creating two periods shouldn't throw.
|
||||
testRunner.createPeriod(new MediaPeriodId(/* periodIndex= */ 0, /* windowSequenceNumber= */ 0));
|
||||
testRunner.createPeriod(new MediaPeriodId(/* periodIndex= */ 0, /* windowSequenceNumber= */ 0));
|
||||
MediaPeriodId mediaPeriodId =
|
||||
new MediaPeriodId(
|
||||
timeline.getUidOfPeriod(/* periodIndex= */ 0), /* windowSequenceNumber= */ 0);
|
||||
testRunner.createPeriod(mediaPeriodId);
|
||||
testRunner.createPeriod(mediaPeriodId);
|
||||
}
|
||||
|
||||
private void assertCompletedAllMediaPeriodLoads(Timeline timeline) {
|
||||
@ -918,11 +935,12 @@ public final class ConcatenatingMediaSourceTest {
|
||||
periodIndex <= window.lastPeriodIndex;
|
||||
periodIndex++) {
|
||||
timeline.getPeriod(periodIndex, period);
|
||||
expectedMediaPeriodIds.add(new MediaPeriodId(periodIndex, windowIndex));
|
||||
Object periodUid = timeline.getUidOfPeriod(periodIndex);
|
||||
expectedMediaPeriodIds.add(new MediaPeriodId(periodUid, windowIndex));
|
||||
for (int adGroupIndex = 0; adGroupIndex < period.getAdGroupCount(); adGroupIndex++) {
|
||||
for (int adIndex = 0; adIndex < period.getAdCountInAdGroup(adGroupIndex); adIndex++) {
|
||||
expectedMediaPeriodIds.add(
|
||||
new MediaPeriodId(periodIndex, adGroupIndex, adIndex, windowIndex));
|
||||
new MediaPeriodId(periodUid, adGroupIndex, adIndex, windowIndex));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -45,11 +45,11 @@ public final class SinglePeriodTimelineTest {
|
||||
public void testGetPeriodPositionDynamicWindowUnknownDuration() {
|
||||
SinglePeriodTimeline timeline = new SinglePeriodTimeline(C.TIME_UNSET, false, true);
|
||||
// Should return null with any positive position projection.
|
||||
Pair<Integer, Long> position = timeline.getPeriodPosition(window, period, 0, C.TIME_UNSET, 1);
|
||||
Pair<Object, Long> position = timeline.getPeriodPosition(window, period, 0, C.TIME_UNSET, 1);
|
||||
assertThat(position).isNull();
|
||||
// Should return (0, 0) without a position projection.
|
||||
position = timeline.getPeriodPosition(window, period, 0, C.TIME_UNSET, 0);
|
||||
assertThat(position.first).isEqualTo(0);
|
||||
assertThat(position.first).isEqualTo(timeline.getUidOfPeriod(0));
|
||||
assertThat(position.second).isEqualTo(0);
|
||||
}
|
||||
|
||||
@ -66,16 +66,16 @@ public final class SinglePeriodTimelineTest {
|
||||
/* isDynamic= */ true,
|
||||
/* tag= */ null);
|
||||
// Should return null with a positive position projection beyond window duration.
|
||||
Pair<Integer, Long> position = timeline.getPeriodPosition(window, period, 0, C.TIME_UNSET,
|
||||
windowDurationUs + 1);
|
||||
Pair<Object, Long> position =
|
||||
timeline.getPeriodPosition(window, period, 0, C.TIME_UNSET, windowDurationUs + 1);
|
||||
assertThat(position).isNull();
|
||||
// Should return (0, duration) with a projection equal to window duration.
|
||||
position = timeline.getPeriodPosition(window, period, 0, C.TIME_UNSET, windowDurationUs);
|
||||
assertThat(position.first).isEqualTo(0);
|
||||
assertThat(position.first).isEqualTo(timeline.getUidOfPeriod(0));
|
||||
assertThat(position.second).isEqualTo(windowDurationUs);
|
||||
// Should return (0, 0) without a position projection.
|
||||
position = timeline.getPeriodPosition(window, period, 0, C.TIME_UNSET, 0);
|
||||
assertThat(position.first).isEqualTo(0);
|
||||
assertThat(position.first).isEqualTo(timeline.getUidOfPeriod(0));
|
||||
assertThat(position.second).isEqualTo(0);
|
||||
}
|
||||
|
||||
|
@ -73,8 +73,8 @@ import java.util.List;
|
||||
private final PlayerEmsgHandler playerEmsgHandler;
|
||||
private final IdentityHashMap<ChunkSampleStream<DashChunkSource>, PlayerTrackEmsgHandler>
|
||||
trackEmsgHandlerBySampleStream;
|
||||
private final EventDispatcher eventDispatcher;
|
||||
|
||||
private EventDispatcher eventDispatcher;
|
||||
private @Nullable Callback callback;
|
||||
private ChunkSampleStream<DashChunkSource>[] sampleStreams;
|
||||
private EventSampleStream[] eventSampleStreams;
|
||||
@ -131,13 +131,6 @@ import java.util.List;
|
||||
*/
|
||||
public void updateManifest(DashManifest manifest, int periodIndex) {
|
||||
this.manifest = manifest;
|
||||
if (this.periodIndex != periodIndex) {
|
||||
eventDispatcher =
|
||||
eventDispatcher.withParameters(
|
||||
/* windowIndex= */ 0,
|
||||
eventDispatcher.mediaPeriodId.copyWithPeriodIndex(periodIndex),
|
||||
manifest.getPeriod(periodIndex).startMs);
|
||||
}
|
||||
this.periodIndex = periodIndex;
|
||||
playerEmsgHandler.updateManifest(manifest);
|
||||
if (sampleStreams != null) {
|
||||
|
@ -631,7 +631,7 @@ public final class DashMediaSource extends BaseMediaSource {
|
||||
|
||||
@Override
|
||||
public MediaPeriod createPeriod(MediaPeriodId periodId, Allocator allocator) {
|
||||
int periodIndex = periodId.periodIndex;
|
||||
int periodIndex = (Integer) periodId.periodUid - firstPeriodId;
|
||||
EventDispatcher periodEventDispatcher =
|
||||
createEventDispatcher(periodId, manifest.getPeriod(periodIndex).startMs);
|
||||
DashMediaPeriod mediaPeriod =
|
||||
|
@ -425,7 +425,6 @@ public final class HlsMediaSource extends BaseMediaSource
|
||||
|
||||
@Override
|
||||
public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) {
|
||||
Assertions.checkArgument(id.periodIndex == 0);
|
||||
EventDispatcher eventDispatcher = createEventDispatcher(id);
|
||||
return new HlsMediaPeriod(
|
||||
extractorFactory,
|
||||
|
@ -525,7 +525,6 @@ public final class SsMediaSource extends BaseMediaSource
|
||||
|
||||
@Override
|
||||
public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) {
|
||||
Assertions.checkArgument(id.periodIndex == 0);
|
||||
EventDispatcher eventDispatcher = createEventDispatcher(id);
|
||||
SsMediaPeriod period =
|
||||
new SsMediaPeriod(
|
||||
|
@ -53,7 +53,7 @@ public class FakeAdaptiveMediaSource extends FakeMediaSource {
|
||||
Allocator allocator,
|
||||
EventDispatcher eventDispatcher,
|
||||
@Nullable TransferListener transferListener) {
|
||||
Period period = timeline.getPeriod(id.periodIndex, new Period());
|
||||
Period period = timeline.getPeriodByUid(id.periodUid, new Period());
|
||||
return new FakeAdaptiveMediaPeriod(
|
||||
trackGroupArray,
|
||||
eventDispatcher,
|
||||
|
@ -111,8 +111,9 @@ public class FakeMediaSource extends BaseMediaSource {
|
||||
public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator) {
|
||||
assertThat(preparedSource).isTrue();
|
||||
assertThat(releasedSource).isFalse();
|
||||
Assertions.checkIndex(id.periodIndex, 0, timeline.getPeriodCount());
|
||||
Period period = timeline.getPeriod(id.periodIndex, new Period());
|
||||
int periodIndex = timeline.getIndexOfPeriod(id.periodUid);
|
||||
Assertions.checkArgument(periodIndex != C.INDEX_UNSET);
|
||||
Period period = timeline.getPeriod(periodIndex, new Period());
|
||||
EventDispatcher eventDispatcher =
|
||||
createEventDispatcher(period.windowIndex, id, period.getPositionInWindowMs());
|
||||
FakeMediaPeriod mediaPeriod =
|
||||
|
@ -251,12 +251,12 @@ public class MediaSourceTestRunner {
|
||||
public void assertPrepareAndReleaseAllPeriods() throws InterruptedException {
|
||||
Timeline.Period period = new Timeline.Period();
|
||||
for (int i = 0; i < timeline.getPeriodCount(); i++) {
|
||||
timeline.getPeriod(i, period);
|
||||
assertPrepareAndReleasePeriod(new MediaPeriodId(i, period.windowIndex));
|
||||
timeline.getPeriod(i, period, /* setIds= */ true);
|
||||
assertPrepareAndReleasePeriod(new MediaPeriodId(period.uid, period.windowIndex));
|
||||
for (int adGroupIndex = 0; adGroupIndex < period.getAdGroupCount(); adGroupIndex++) {
|
||||
for (int adIndex = 0; adIndex < period.getAdCountInAdGroup(adGroupIndex); adIndex++) {
|
||||
assertPrepareAndReleasePeriod(
|
||||
new MediaPeriodId(i, adGroupIndex, adIndex, period.windowIndex));
|
||||
new MediaPeriodId(period.uid, adGroupIndex, adIndex, period.windowIndex));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -272,7 +272,7 @@ public class MediaSourceTestRunner {
|
||||
// to releasePeriod.
|
||||
MediaPeriodId secondMediaPeriodId =
|
||||
new MediaPeriodId(
|
||||
mediaPeriodId.periodIndex,
|
||||
mediaPeriodId.periodUid,
|
||||
mediaPeriodId.adGroupIndex,
|
||||
mediaPeriodId.adIndexInAdGroup,
|
||||
mediaPeriodId.windowSequenceNumber + 1000);
|
||||
@ -322,8 +322,8 @@ public class MediaSourceTestRunner {
|
||||
int windowIndex = windowIndexAndMediaPeriodId.first;
|
||||
MediaPeriodId mediaPeriodId = windowIndexAndMediaPeriodId.second;
|
||||
if (expectedLoads.remove(mediaPeriodId)) {
|
||||
assertThat(windowIndex)
|
||||
.isEqualTo(timeline.getPeriod(mediaPeriodId.periodIndex, period).windowIndex);
|
||||
int periodIndex = timeline.getIndexOfPeriod(mediaPeriodId.periodUid);
|
||||
assertThat(windowIndex).isEqualTo(timeline.getPeriod(periodIndex, period).windowIndex);
|
||||
}
|
||||
}
|
||||
assertWithMessage("Not all expected media source loads have been completed.")
|
||||
|
Loading…
x
Reference in New Issue
Block a user