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