mirror of
https://github.com/samsonjs/media.git
synced 2026-04-27 15:07:40 +00:00
Add positions and new reasons to onPositionDiscontinuity
PiperOrigin-RevId: 364861539
This commit is contained in:
parent
f19ab4aa8b
commit
dc4148d576
26 changed files with 1586 additions and 192 deletions
|
|
@ -2,6 +2,17 @@
|
||||||
|
|
||||||
### dev-v2 (not yet released)
|
### dev-v2 (not yet released)
|
||||||
|
|
||||||
|
* Core Library:
|
||||||
|
* Add position info of the old and the new position as arguments to
|
||||||
|
`EventListener.onPositionDiscontinuity`. Add the new reasons
|
||||||
|
`DISCONTINUITY_REASON_SKIP` and `DISCONTINUITY_REASON_REMOVE` and rename
|
||||||
|
`DISCONTINUITY_REASON_PERIOD_TRANSITION` to
|
||||||
|
`DISCONTINUITY_REASON_AUTO_TRANSITION`. Remove
|
||||||
|
`DISCONTINUITY_REASON_AD_INSERTION` for which
|
||||||
|
`DISCONTINUITY_REASON_AUTO_TRANSITION` is used instead. Deprecate the
|
||||||
|
`onPositionDiscontinuity(int)` callback
|
||||||
|
([#6163](https://github.com/google/ExoPlayer/issues/6163),
|
||||||
|
[#4768](https://github.com/google/ExoPlayer/issues/4768)).
|
||||||
* UI:
|
* UI:
|
||||||
* Add builder for `PlayerNotificationManager`.
|
* Add builder for `PlayerNotificationManager`.
|
||||||
* Add group setting to `PlayerNotificationManager`.
|
* Add group setting to `PlayerNotificationManager`.
|
||||||
|
|
|
||||||
|
|
@ -460,6 +460,7 @@ public final class CastPlayer extends BasePlayer {
|
||||||
pendingSeekCount++;
|
pendingSeekCount++;
|
||||||
pendingSeekWindowIndex = windowIndex;
|
pendingSeekWindowIndex = windowIndex;
|
||||||
pendingSeekPositionMs = positionMs;
|
pendingSeekPositionMs = positionMs;
|
||||||
|
// TODO(b/181262841): call new onPositionDiscontinuity callback
|
||||||
listeners.queueEvent(
|
listeners.queueEvent(
|
||||||
Player.EVENT_POSITION_DISCONTINUITY,
|
Player.EVENT_POSITION_DISCONTINUITY,
|
||||||
listener -> listener.onPositionDiscontinuity(DISCONTINUITY_REASON_SEEK));
|
listener -> listener.onPositionDiscontinuity(DISCONTINUITY_REASON_SEEK));
|
||||||
|
|
@ -630,6 +631,8 @@ public final class CastPlayer extends BasePlayer {
|
||||||
|
|
||||||
// Internal methods.
|
// Internal methods.
|
||||||
|
|
||||||
|
// Call deprecated callbacks.
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
private void updateInternalStateAndNotifyIfChanged() {
|
private void updateInternalStateAndNotifyIfChanged() {
|
||||||
if (remoteMediaClient == null) {
|
if (remoteMediaClient == null) {
|
||||||
// There is no session. We leave the state of the player as it is now.
|
// There is no session. We leave the state of the player as it is now.
|
||||||
|
|
@ -648,9 +651,10 @@ public final class CastPlayer extends BasePlayer {
|
||||||
int currentWindowIndex = fetchCurrentWindowIndex(remoteMediaClient, currentTimeline);
|
int currentWindowIndex = fetchCurrentWindowIndex(remoteMediaClient, currentTimeline);
|
||||||
if (this.currentWindowIndex != currentWindowIndex && pendingSeekCount == 0) {
|
if (this.currentWindowIndex != currentWindowIndex && pendingSeekCount == 0) {
|
||||||
this.currentWindowIndex = currentWindowIndex;
|
this.currentWindowIndex = currentWindowIndex;
|
||||||
|
// TODO(b/181262841): call new onPositionDiscontinuity callback
|
||||||
listeners.queueEvent(
|
listeners.queueEvent(
|
||||||
Player.EVENT_POSITION_DISCONTINUITY,
|
Player.EVENT_POSITION_DISCONTINUITY,
|
||||||
listener -> listener.onPositionDiscontinuity(DISCONTINUITY_REASON_PERIOD_TRANSITION));
|
listener -> listener.onPositionDiscontinuity(DISCONTINUITY_REASON_AUTO_TRANSITION));
|
||||||
listeners.queueEvent(
|
listeners.queueEvent(
|
||||||
Player.EVENT_MEDIA_ITEM_TRANSITION,
|
Player.EVENT_MEDIA_ITEM_TRANSITION,
|
||||||
listener ->
|
listener ->
|
||||||
|
|
|
||||||
|
|
@ -468,7 +468,10 @@ import java.util.Map;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPositionDiscontinuity(@Player.DiscontinuityReason int reason) {
|
public void onPositionDiscontinuity(
|
||||||
|
Player.PositionInfo oldPosition,
|
||||||
|
Player.PositionInfo newPosition,
|
||||||
|
@Player.DiscontinuityReason int reason) {
|
||||||
handleTimelineOrPositionChanged();
|
handleTimelineOrPositionChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -613,7 +613,10 @@ public final class ImaAdsLoader implements Player.EventListener, AdsLoader {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPositionDiscontinuity(@Player.DiscontinuityReason int reason) {
|
public void onPositionDiscontinuity(
|
||||||
|
Player.PositionInfo oldPosition,
|
||||||
|
Player.PositionInfo newPosition,
|
||||||
|
@Player.DiscontinuityReason int reason) {
|
||||||
maybeUpdateCurrentAdTagLoader();
|
maybeUpdateCurrentAdTagLoader();
|
||||||
maybePreloadNextPeriodAds();
|
maybePreloadNextPeriodAds();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,8 @@ import com.google.android.exoplayer2.util.ListenerSet;
|
||||||
|
|
||||||
private final ListenerSet<EventListener> listeners;
|
private final ListenerSet<EventListener> listeners;
|
||||||
private final Timeline.Period period;
|
private final Timeline.Period period;
|
||||||
|
private final Object windowUid = new Object();
|
||||||
|
private final Object periodUid = new Object();
|
||||||
|
|
||||||
private Timeline timeline;
|
private Timeline timeline;
|
||||||
@Player.State private int state;
|
@Player.State private int state;
|
||||||
|
|
@ -65,6 +67,16 @@ import com.google.android.exoplayer2.util.ListenerSet;
|
||||||
*/
|
*/
|
||||||
public void setPlayingContentPosition(int periodIndex, long positionMs) {
|
public void setPlayingContentPosition(int periodIndex, long positionMs) {
|
||||||
boolean notify = isPlayingAd;
|
boolean notify = isPlayingAd;
|
||||||
|
PositionInfo oldPosition =
|
||||||
|
new PositionInfo(
|
||||||
|
windowUid,
|
||||||
|
/* windowIndex= */ 0,
|
||||||
|
periodUid,
|
||||||
|
/* periodIndex= */ 0,
|
||||||
|
this.positionMs,
|
||||||
|
this.contentPositionMs,
|
||||||
|
this.adGroupIndex,
|
||||||
|
this.adIndexInAdGroup);
|
||||||
isPlayingAd = false;
|
isPlayingAd = false;
|
||||||
adGroupIndex = C.INDEX_UNSET;
|
adGroupIndex = C.INDEX_UNSET;
|
||||||
adIndexInAdGroup = C.INDEX_UNSET;
|
adIndexInAdGroup = C.INDEX_UNSET;
|
||||||
|
|
@ -72,9 +84,21 @@ import com.google.android.exoplayer2.util.ListenerSet;
|
||||||
this.positionMs = positionMs;
|
this.positionMs = positionMs;
|
||||||
contentPositionMs = positionMs;
|
contentPositionMs = positionMs;
|
||||||
if (notify) {
|
if (notify) {
|
||||||
|
PositionInfo newPosition =
|
||||||
|
new PositionInfo(
|
||||||
|
windowUid,
|
||||||
|
/* windowIndex= */ 0,
|
||||||
|
periodUid,
|
||||||
|
/* periodIndex= */ 0,
|
||||||
|
positionMs,
|
||||||
|
this.contentPositionMs,
|
||||||
|
this.adGroupIndex,
|
||||||
|
this.adIndexInAdGroup);
|
||||||
listeners.sendEvent(
|
listeners.sendEvent(
|
||||||
Player.EVENT_POSITION_DISCONTINUITY,
|
Player.EVENT_POSITION_DISCONTINUITY,
|
||||||
listener -> listener.onPositionDiscontinuity(DISCONTINUITY_REASON_AD_INSERTION));
|
listener ->
|
||||||
|
listener.onPositionDiscontinuity(
|
||||||
|
oldPosition, newPosition, DISCONTINUITY_REASON_AUTO_TRANSITION));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -90,6 +114,16 @@ import com.google.android.exoplayer2.util.ListenerSet;
|
||||||
long positionMs,
|
long positionMs,
|
||||||
long contentPositionMs) {
|
long contentPositionMs) {
|
||||||
boolean notify = !isPlayingAd || this.adIndexInAdGroup != adIndexInAdGroup;
|
boolean notify = !isPlayingAd || this.adIndexInAdGroup != adIndexInAdGroup;
|
||||||
|
PositionInfo oldPosition =
|
||||||
|
new PositionInfo(
|
||||||
|
windowUid,
|
||||||
|
/* windowIndex= */ 0,
|
||||||
|
periodUid,
|
||||||
|
/* periodIndex= */ 0,
|
||||||
|
this.positionMs,
|
||||||
|
this.contentPositionMs,
|
||||||
|
this.adGroupIndex,
|
||||||
|
this.adIndexInAdGroup);
|
||||||
isPlayingAd = true;
|
isPlayingAd = true;
|
||||||
this.periodIndex = periodIndex;
|
this.periodIndex = periodIndex;
|
||||||
this.adGroupIndex = adGroupIndex;
|
this.adGroupIndex = adGroupIndex;
|
||||||
|
|
@ -97,9 +131,21 @@ import com.google.android.exoplayer2.util.ListenerSet;
|
||||||
this.positionMs = positionMs;
|
this.positionMs = positionMs;
|
||||||
this.contentPositionMs = contentPositionMs;
|
this.contentPositionMs = contentPositionMs;
|
||||||
if (notify) {
|
if (notify) {
|
||||||
|
PositionInfo newPosition =
|
||||||
|
new PositionInfo(
|
||||||
|
windowUid,
|
||||||
|
/* windowIndex= */ 0,
|
||||||
|
periodUid,
|
||||||
|
/* periodIndex= */ 0,
|
||||||
|
positionMs,
|
||||||
|
contentPositionMs,
|
||||||
|
adGroupIndex,
|
||||||
|
adIndexInAdGroup);
|
||||||
listeners.sendEvent(
|
listeners.sendEvent(
|
||||||
EVENT_POSITION_DISCONTINUITY,
|
EVENT_POSITION_DISCONTINUITY,
|
||||||
listener -> listener.onPositionDiscontinuity(DISCONTINUITY_REASON_AD_INSERTION));
|
listener ->
|
||||||
|
listener.onPositionDiscontinuity(
|
||||||
|
oldPosition, newPosition, DISCONTINUITY_REASON_AUTO_TRANSITION));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -281,7 +281,26 @@ public final class ImaAdsLoaderTest {
|
||||||
videoAdPlayer.pauseAd(TEST_AD_MEDIA_INFO);
|
videoAdPlayer.pauseAd(TEST_AD_MEDIA_INFO);
|
||||||
videoAdPlayer.stopAd(TEST_AD_MEDIA_INFO);
|
videoAdPlayer.stopAd(TEST_AD_MEDIA_INFO);
|
||||||
imaAdsLoader.onPlayerError(ExoPlaybackException.createForSource(new IOException()));
|
imaAdsLoader.onPlayerError(ExoPlaybackException.createForSource(new IOException()));
|
||||||
imaAdsLoader.onPositionDiscontinuity(Player.DISCONTINUITY_REASON_SEEK);
|
imaAdsLoader.onPositionDiscontinuity(
|
||||||
|
new Player.PositionInfo(
|
||||||
|
/* windowUid= */ new Object(),
|
||||||
|
/* windowIndex= */ 0,
|
||||||
|
/* periodUid= */ new Object(),
|
||||||
|
/* periodIndex= */ 0,
|
||||||
|
/* positionMs= */ 10_000,
|
||||||
|
/* contentPositionMs= */ 0,
|
||||||
|
/* adGroupIndex= */ -1,
|
||||||
|
/* adIndexInAdGroup= */ -1),
|
||||||
|
new Player.PositionInfo(
|
||||||
|
/* windowUid= */ new Object(),
|
||||||
|
/* windowIndex= */ 1,
|
||||||
|
/* periodUid= */ new Object(),
|
||||||
|
/* periodIndex= */ 0,
|
||||||
|
/* positionMs= */ 20_000,
|
||||||
|
/* contentPositionMs= */ 0,
|
||||||
|
/* adGroupIndex= */ -1,
|
||||||
|
/* adIndexInAdGroup= */ -1),
|
||||||
|
Player.DISCONTINUITY_REASON_SEEK);
|
||||||
adEventListener.onAdEvent(getAdEvent(AdEventType.CONTENT_RESUME_REQUESTED, /* ad= */ null));
|
adEventListener.onAdEvent(getAdEvent(AdEventType.CONTENT_RESUME_REQUESTED, /* ad= */ null));
|
||||||
imaAdsLoader.handlePrepareError(
|
imaAdsLoader.handlePrepareError(
|
||||||
adsMediaSource, /* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0, new IOException());
|
adsMediaSource, /* adGroupIndex= */ 0, /* adIndexInAdGroup= */ 0, new IOException());
|
||||||
|
|
|
||||||
|
|
@ -306,7 +306,10 @@ public final class LeanbackPlayerAdapter extends PlayerAdapter implements Runnab
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPositionDiscontinuity(@DiscontinuityReason int reason) {
|
public void onPositionDiscontinuity(
|
||||||
|
Player.PositionInfo oldPosition,
|
||||||
|
Player.PositionInfo newPosition,
|
||||||
|
@DiscontinuityReason int reason) {
|
||||||
Callback callback = getCallback();
|
Callback callback = getCallback();
|
||||||
callback.onCurrentPositionChanged(LeanbackPlayerAdapter.this);
|
callback.onCurrentPositionChanged(LeanbackPlayerAdapter.this);
|
||||||
callback.onBufferedPositionChanged(LeanbackPlayerAdapter.this);
|
callback.onBufferedPositionChanged(LeanbackPlayerAdapter.this);
|
||||||
|
|
|
||||||
|
|
@ -437,7 +437,7 @@ import java.util.List;
|
||||||
case Player.STATE_READY:
|
case Player.STATE_READY:
|
||||||
if (!prepared) {
|
if (!prepared) {
|
||||||
prepared = true;
|
prepared = true;
|
||||||
handlePositionDiscontinuity(Player.DISCONTINUITY_REASON_PERIOD_TRANSITION);
|
handlePositionDiscontinuity(Player.DISCONTINUITY_REASON_AUTO_TRANSITION);
|
||||||
listener.onPrepared(
|
listener.onPrepared(
|
||||||
Assertions.checkNotNull(getCurrentMediaItem()), player.getBufferedPercentage());
|
Assertions.checkNotNull(getCurrentMediaItem()), player.getBufferedPercentage());
|
||||||
}
|
}
|
||||||
|
|
@ -517,9 +517,11 @@ import java.util.List;
|
||||||
int currentWindowIndex = getCurrentMediaItemIndex();
|
int currentWindowIndex = getCurrentMediaItemIndex();
|
||||||
if (this.currentWindowIndex != currentWindowIndex) {
|
if (this.currentWindowIndex != currentWindowIndex) {
|
||||||
this.currentWindowIndex = currentWindowIndex;
|
this.currentWindowIndex = currentWindowIndex;
|
||||||
androidx.media2.common.MediaItem currentMediaItem =
|
if (currentWindowIndex != C.INDEX_UNSET) {
|
||||||
Assertions.checkNotNull(getCurrentMediaItem());
|
androidx.media2.common.MediaItem currentMediaItem =
|
||||||
listener.onCurrentMediaItemChanged(currentMediaItem);
|
Assertions.checkNotNull(getCurrentMediaItem());
|
||||||
|
listener.onCurrentMediaItemChanged(currentMediaItem);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
listener.onSeekCompleted();
|
listener.onSeekCompleted();
|
||||||
}
|
}
|
||||||
|
|
@ -597,7 +599,10 @@ import java.util.List;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPositionDiscontinuity(@Player.DiscontinuityReason int reason) {
|
public void onPositionDiscontinuity(
|
||||||
|
Player.PositionInfo oldPosition,
|
||||||
|
Player.PositionInfo newPosition,
|
||||||
|
@Player.DiscontinuityReason int reason) {
|
||||||
handlePositionDiscontinuity(reason);
|
handlePositionDiscontinuity(reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@
|
||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer2;
|
package com.google.android.exoplayer2;
|
||||||
|
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.view.Surface;
|
import android.view.Surface;
|
||||||
|
|
@ -40,6 +39,7 @@ import com.google.android.exoplayer2.util.Util;
|
||||||
import com.google.android.exoplayer2.video.VideoFrameMetadataListener;
|
import com.google.android.exoplayer2.video.VideoFrameMetadataListener;
|
||||||
import com.google.android.exoplayer2.video.VideoListener;
|
import com.google.android.exoplayer2.video.VideoListener;
|
||||||
import com.google.android.exoplayer2.video.spherical.CameraMotionListener;
|
import com.google.android.exoplayer2.video.spherical.CameraMotionListener;
|
||||||
|
import com.google.common.base.Objects;
|
||||||
import java.lang.annotation.Documented;
|
import java.lang.annotation.Documented;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
@ -396,10 +396,9 @@ public interface Player {
|
||||||
/**
|
/**
|
||||||
* Called when the timeline has been refreshed.
|
* Called when the timeline has been refreshed.
|
||||||
*
|
*
|
||||||
* <p>Note that if the timeline has changed then a position discontinuity may also have
|
* <p>Note that the current window or period index may change as a result of a timeline change.
|
||||||
* occurred. For example, the current period index may have changed as a result of periods being
|
* If playback can't continue smoothly because of this timeline change, a separate {@link
|
||||||
* added or removed from the timeline. This will <em>not</em> be reported via a separate call to
|
* #onPositionDiscontinuity(PositionInfo, PositionInfo, int)} callback will be triggered.
|
||||||
* {@link #onPositionDiscontinuity(int)}.
|
|
||||||
*
|
*
|
||||||
* <p>{@link #onEvents(Player, Events)} will also be called to report this event along with
|
* <p>{@link #onEvents(Player, Events)} will also be called to report this event along with
|
||||||
* other events that happen in the same {@link Looper} message queue iteration.
|
* other events that happen in the same {@link Looper} message queue iteration.
|
||||||
|
|
@ -576,21 +575,27 @@ public interface Player {
|
||||||
default void onPlayerError(ExoPlaybackException error) {}
|
default void onPlayerError(ExoPlaybackException error) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when a position discontinuity occurs without a change to the timeline. A position
|
* @deprecated Use {@link #onPositionDiscontinuity(PositionInfo, PositionInfo, int)} instead.
|
||||||
* discontinuity occurs when the current window or period index changes (as a result of playback
|
*/
|
||||||
* transitioning from one period in the timeline to the next), or when the playback position
|
@Deprecated
|
||||||
* jumps within the period currently being played (as a result of a seek being performed, or
|
default void onPositionDiscontinuity(@DiscontinuityReason int reason) {}
|
||||||
* when the source introduces a discontinuity internally).
|
|
||||||
|
/**
|
||||||
|
* Called when a position discontinuity occurs.
|
||||||
*
|
*
|
||||||
* <p>When a position discontinuity occurs as a result of a change to the timeline this method
|
* <p>A position discontinuity occurs when the playing period changes, the playback position
|
||||||
* is <em>not</em> called. {@link #onTimelineChanged(Timeline, int)} is called in this case.
|
* jumps within the period currently being played, or when the playing period has been skipped
|
||||||
|
* or removed.
|
||||||
*
|
*
|
||||||
* <p>{@link #onEvents(Player, Events)} will also be called to report this event along with
|
* <p>{@link #onEvents(Player, Events)} will also be called to report this event along with
|
||||||
* other events that happen in the same {@link Looper} message queue iteration.
|
* other events that happen in the same {@link Looper} message queue iteration.
|
||||||
*
|
*
|
||||||
|
* @param oldPosition The position before the discontinuity.
|
||||||
|
* @param newPosition The position after the discontinuity.
|
||||||
* @param reason The {@link DiscontinuityReason} responsible for the discontinuity.
|
* @param reason The {@link DiscontinuityReason} responsible for the discontinuity.
|
||||||
*/
|
*/
|
||||||
default void onPositionDiscontinuity(@DiscontinuityReason int reason) {}
|
default void onPositionDiscontinuity(
|
||||||
|
PositionInfo oldPosition, PositionInfo newPosition, @DiscontinuityReason int reason) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when the current playback parameters change. The playback parameters may change due to
|
* Called when the current playback parameters change. The playback parameters may change due to
|
||||||
|
|
@ -607,7 +612,8 @@ public interface Player {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Seeks are processed without delay. Listen to {@link
|
* @deprecated Seeks are processed without delay. Listen to {@link
|
||||||
* #onPositionDiscontinuity(int)} with reason {@link #DISCONTINUITY_REASON_SEEK} instead.
|
* #onPositionDiscontinuity(PositionInfo, PositionInfo, int)} with reason {@link
|
||||||
|
* #DISCONTINUITY_REASON_SEEK} instead.
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
default void onSeekProcessed() {}
|
default void onSeekProcessed() {}
|
||||||
|
|
@ -698,6 +704,94 @@ public interface Player {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Position info describing a playback position involved in a discontinuity. */
|
||||||
|
final class PositionInfo {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The UID of the window, or {@code null}, if the timeline is {@link Timeline#isEmpty() empty}.
|
||||||
|
*/
|
||||||
|
@Nullable public final Object windowUid;
|
||||||
|
/** The window index. */
|
||||||
|
public final int windowIndex;
|
||||||
|
/**
|
||||||
|
* The UID of the period, or {@code null}, if the timeline is {@link Timeline#isEmpty() empty}.
|
||||||
|
*/
|
||||||
|
@Nullable public final Object periodUid;
|
||||||
|
/** The period index. */
|
||||||
|
public final int periodIndex;
|
||||||
|
/** The playback position, in milliseconds. */
|
||||||
|
public final long positionMs;
|
||||||
|
/**
|
||||||
|
* The content position, in milliseconds.
|
||||||
|
*
|
||||||
|
* <p>If {@link #adGroupIndex} is {@link C#INDEX_UNSET}, this is the same as {@link
|
||||||
|
* #positionMs}.
|
||||||
|
*/
|
||||||
|
public final long contentPositionMs;
|
||||||
|
/**
|
||||||
|
* The ad group index if the playback position is within an ad, {@link C#INDEX_UNSET} otherwise.
|
||||||
|
*/
|
||||||
|
public final int adGroupIndex;
|
||||||
|
/**
|
||||||
|
* The index of the ad within the ad group if the playback position is within an ad, {@link
|
||||||
|
* C#INDEX_UNSET} otherwise.
|
||||||
|
*/
|
||||||
|
public final int adIndexInAdGroup;
|
||||||
|
|
||||||
|
/** Creates an instance. */
|
||||||
|
public PositionInfo(
|
||||||
|
@Nullable Object windowUid,
|
||||||
|
int windowIndex,
|
||||||
|
@Nullable Object periodUid,
|
||||||
|
int periodIndex,
|
||||||
|
long positionMs,
|
||||||
|
long contentPositionMs,
|
||||||
|
int adGroupIndex,
|
||||||
|
int adIndexInAdGroup) {
|
||||||
|
this.windowUid = windowUid;
|
||||||
|
this.windowIndex = windowIndex;
|
||||||
|
this.periodUid = periodUid;
|
||||||
|
this.periodIndex = periodIndex;
|
||||||
|
this.positionMs = positionMs;
|
||||||
|
this.contentPositionMs = contentPositionMs;
|
||||||
|
this.adGroupIndex = adGroupIndex;
|
||||||
|
this.adIndexInAdGroup = adIndexInAdGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(@Nullable Object o) {
|
||||||
|
if (this == o) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (o == null || getClass() != o.getClass()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
PositionInfo that = (PositionInfo) o;
|
||||||
|
return windowIndex == that.windowIndex
|
||||||
|
&& periodIndex == that.periodIndex
|
||||||
|
&& positionMs == that.positionMs
|
||||||
|
&& contentPositionMs == that.contentPositionMs
|
||||||
|
&& adGroupIndex == that.adGroupIndex
|
||||||
|
&& adIndexInAdGroup == that.adIndexInAdGroup
|
||||||
|
&& Objects.equal(windowUid, that.windowUid)
|
||||||
|
&& Objects.equal(periodUid, that.periodUid);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hashCode(
|
||||||
|
windowUid,
|
||||||
|
windowIndex,
|
||||||
|
periodUid,
|
||||||
|
periodIndex,
|
||||||
|
windowIndex,
|
||||||
|
positionMs,
|
||||||
|
contentPositionMs,
|
||||||
|
adGroupIndex,
|
||||||
|
adIndexInAdGroup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A set of {@link Command commands}.
|
* A set of {@link Command commands}.
|
||||||
*
|
*
|
||||||
|
|
@ -933,25 +1027,30 @@ public interface Player {
|
||||||
int REPEAT_MODE_ALL = 2;
|
int REPEAT_MODE_ALL = 2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reasons for position discontinuities. One of {@link #DISCONTINUITY_REASON_PERIOD_TRANSITION},
|
* Reasons for position discontinuities. One of {@link #DISCONTINUITY_REASON_AUTO_TRANSITION},
|
||||||
* {@link #DISCONTINUITY_REASON_SEEK}, {@link #DISCONTINUITY_REASON_SEEK_ADJUSTMENT}, {@link
|
* {@link #DISCONTINUITY_REASON_SEEK}, {@link #DISCONTINUITY_REASON_SEEK_ADJUSTMENT}, {@link
|
||||||
* #DISCONTINUITY_REASON_AD_INSERTION} or {@link #DISCONTINUITY_REASON_INTERNAL}.
|
* #DISCONTINUITY_REASON_SKIP}, {@link #DISCONTINUITY_REASON_REMOVE} or {@link
|
||||||
|
* #DISCONTINUITY_REASON_INTERNAL}.
|
||||||
*/
|
*/
|
||||||
@Documented
|
@Documented
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
@IntDef({
|
@IntDef({
|
||||||
DISCONTINUITY_REASON_PERIOD_TRANSITION,
|
DISCONTINUITY_REASON_AUTO_TRANSITION,
|
||||||
DISCONTINUITY_REASON_SEEK,
|
DISCONTINUITY_REASON_SEEK,
|
||||||
DISCONTINUITY_REASON_SEEK_ADJUSTMENT,
|
DISCONTINUITY_REASON_SEEK_ADJUSTMENT,
|
||||||
DISCONTINUITY_REASON_AD_INSERTION,
|
DISCONTINUITY_REASON_SKIP,
|
||||||
|
DISCONTINUITY_REASON_REMOVE,
|
||||||
DISCONTINUITY_REASON_INTERNAL
|
DISCONTINUITY_REASON_INTERNAL
|
||||||
})
|
})
|
||||||
@interface DiscontinuityReason {}
|
@interface DiscontinuityReason {}
|
||||||
/**
|
/**
|
||||||
* Automatic playback transition from one period in the timeline to the next. The period index may
|
* Automatic playback transition from one period in the timeline to the next. The period index may
|
||||||
* be the same as it was before the discontinuity in case the current period is repeated.
|
* be the same as it was before the discontinuity in case the current period is repeated.
|
||||||
|
*
|
||||||
|
* <p>This reason also indicates an automatic transition from the content period to an inserted ad
|
||||||
|
* period or vice versa.
|
||||||
*/
|
*/
|
||||||
int DISCONTINUITY_REASON_PERIOD_TRANSITION = 0;
|
int DISCONTINUITY_REASON_AUTO_TRANSITION = 0;
|
||||||
/** Seek within the current period or to another period. */
|
/** Seek within the current period or to another period. */
|
||||||
int DISCONTINUITY_REASON_SEEK = 1;
|
int DISCONTINUITY_REASON_SEEK = 1;
|
||||||
/**
|
/**
|
||||||
|
|
@ -959,10 +1058,12 @@ public interface Player {
|
||||||
* permitted to be inexact.
|
* permitted to be inexact.
|
||||||
*/
|
*/
|
||||||
int DISCONTINUITY_REASON_SEEK_ADJUSTMENT = 2;
|
int DISCONTINUITY_REASON_SEEK_ADJUSTMENT = 2;
|
||||||
/** Discontinuity to or from an ad within one period in the timeline. */
|
/** Discontinuity introduced by a skipped period (for instance a skipped ad). */
|
||||||
int DISCONTINUITY_REASON_AD_INSERTION = 3;
|
int DISCONTINUITY_REASON_SKIP = 3;
|
||||||
|
/** Discontinuity caused by the removal of the current period from the {@link Timeline}. */
|
||||||
|
int DISCONTINUITY_REASON_REMOVE = 4;
|
||||||
/** Discontinuity introduced internally by the source. */
|
/** Discontinuity introduced internally by the source. */
|
||||||
int DISCONTINUITY_REASON_INTERNAL = 4;
|
int DISCONTINUITY_REASON_INTERNAL = 5;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reasons for timeline changes. One of {@link #TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED} or {@link
|
* Reasons for timeline changes. One of {@link #TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED} or {@link
|
||||||
|
|
@ -1053,7 +1154,10 @@ public interface Player {
|
||||||
int EVENT_SHUFFLE_MODE_ENABLED_CHANGED = 10;
|
int EVENT_SHUFFLE_MODE_ENABLED_CHANGED = 10;
|
||||||
/** {@link #getPlayerError()} changed. */
|
/** {@link #getPlayerError()} changed. */
|
||||||
int EVENT_PLAYER_ERROR = 11;
|
int EVENT_PLAYER_ERROR = 11;
|
||||||
/** A position discontinuity occurred. See {@link EventListener#onPositionDiscontinuity(int)}. */
|
/**
|
||||||
|
* A position discontinuity occurred. See {@link
|
||||||
|
* EventListener#onPositionDiscontinuity(PositionInfo, PositionInfo, int)}.
|
||||||
|
*/
|
||||||
int EVENT_POSITION_DISCONTINUITY = 12;
|
int EVENT_POSITION_DISCONTINUITY = 12;
|
||||||
/** {@link #getPlaybackParameters()} changed. */
|
/** {@link #getPlaybackParameters()} changed. */
|
||||||
int EVENT_PLAYBACK_PARAMETERS_CHANGED = 13;
|
int EVENT_PLAYBACK_PARAMETERS_CHANGED = 13;
|
||||||
|
|
|
||||||
|
|
@ -87,8 +87,8 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
@RepeatMode private int repeatMode;
|
@RepeatMode private int repeatMode;
|
||||||
private boolean shuffleModeEnabled;
|
private boolean shuffleModeEnabled;
|
||||||
private int pendingOperationAcks;
|
private int pendingOperationAcks;
|
||||||
private boolean hasPendingDiscontinuity;
|
|
||||||
@DiscontinuityReason private int pendingDiscontinuityReason;
|
@DiscontinuityReason private int pendingDiscontinuityReason;
|
||||||
|
private boolean pendingDiscontinuity;
|
||||||
@PlayWhenReadyChangeReason private int pendingPlayWhenReadyChangeReason;
|
@PlayWhenReadyChangeReason private int pendingPlayWhenReadyChangeReason;
|
||||||
private boolean foregroundMode;
|
private boolean foregroundMode;
|
||||||
private SeekParameters seekParameters;
|
private SeekParameters seekParameters;
|
||||||
|
|
@ -367,11 +367,13 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
internalPlayer.prepare();
|
internalPlayer.prepare();
|
||||||
updatePlaybackInfo(
|
updatePlaybackInfo(
|
||||||
playbackInfo,
|
playbackInfo,
|
||||||
/* positionDiscontinuity= */ false,
|
|
||||||
/* ignored */ DISCONTINUITY_REASON_INTERNAL,
|
|
||||||
/* ignored */ TIMELINE_CHANGE_REASON_SOURCE_UPDATE,
|
/* ignored */ TIMELINE_CHANGE_REASON_SOURCE_UPDATE,
|
||||||
/* ignored */ PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST,
|
/* ignored */ PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST,
|
||||||
/* seekProcessed= */ false);
|
/* seekProcessed= */ false,
|
||||||
|
/* positionDiscontinuity= */ false,
|
||||||
|
/* ignored */ DISCONTINUITY_REASON_INTERNAL,
|
||||||
|
/* ignored */ C.TIME_UNSET,
|
||||||
|
/* ignored */ C.INDEX_UNSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -479,24 +481,30 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
internalPlayer.addMediaSources(index, holders, shuffleOrder);
|
internalPlayer.addMediaSources(index, holders, shuffleOrder);
|
||||||
updatePlaybackInfo(
|
updatePlaybackInfo(
|
||||||
newPlaybackInfo,
|
newPlaybackInfo,
|
||||||
/* positionDiscontinuity= */ false,
|
|
||||||
/* ignored */ DISCONTINUITY_REASON_INTERNAL,
|
|
||||||
/* timelineChangeReason= */ TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED,
|
/* timelineChangeReason= */ TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED,
|
||||||
/* ignored */ PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST,
|
/* ignored */ PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST,
|
||||||
/* seekProcessed= */ false);
|
/* seekProcessed= */ false,
|
||||||
|
/* positionDiscontinuity= */ false,
|
||||||
|
/* ignored */ DISCONTINUITY_REASON_INTERNAL,
|
||||||
|
/* ignored */ C.TIME_UNSET,
|
||||||
|
/* ignored */ C.INDEX_UNSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void removeMediaItems(int fromIndex, int toIndex) {
|
public void removeMediaItems(int fromIndex, int toIndex) {
|
||||||
toIndex = min(toIndex, mediaSourceHolderSnapshots.size());
|
toIndex = min(toIndex, mediaSourceHolderSnapshots.size());
|
||||||
PlaybackInfo playbackInfo = removeMediaItemsInternal(fromIndex, toIndex);
|
PlaybackInfo newPlaybackInfo = removeMediaItemsInternal(fromIndex, toIndex);
|
||||||
|
boolean positionDiscontinuity =
|
||||||
|
!newPlaybackInfo.periodId.periodUid.equals(playbackInfo.periodId.periodUid);
|
||||||
updatePlaybackInfo(
|
updatePlaybackInfo(
|
||||||
playbackInfo,
|
newPlaybackInfo,
|
||||||
/* positionDiscontinuity= */ false,
|
|
||||||
/* ignored */ Player.DISCONTINUITY_REASON_INTERNAL,
|
|
||||||
/* timelineChangeReason= */ TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED,
|
/* timelineChangeReason= */ TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED,
|
||||||
/* ignored */ PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST,
|
/* ignored */ PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST,
|
||||||
/* seekProcessed= */ false);
|
/* seekProcessed= */ false,
|
||||||
|
positionDiscontinuity,
|
||||||
|
Player.DISCONTINUITY_REASON_REMOVE,
|
||||||
|
/* discontinuityWindowStartPositionUs= */ getCurrentPositionUsInternal(newPlaybackInfo),
|
||||||
|
/* ignored */ C.INDEX_UNSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -519,11 +527,13 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
internalPlayer.moveMediaSources(fromIndex, toIndex, newFromIndex, shuffleOrder);
|
internalPlayer.moveMediaSources(fromIndex, toIndex, newFromIndex, shuffleOrder);
|
||||||
updatePlaybackInfo(
|
updatePlaybackInfo(
|
||||||
newPlaybackInfo,
|
newPlaybackInfo,
|
||||||
/* positionDiscontinuity= */ false,
|
|
||||||
/* ignored */ DISCONTINUITY_REASON_INTERNAL,
|
|
||||||
/* timelineChangeReason= */ TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED,
|
/* timelineChangeReason= */ TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED,
|
||||||
/* ignored */ PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST,
|
/* ignored */ PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST,
|
||||||
/* seekProcessed= */ false);
|
/* seekProcessed= */ false,
|
||||||
|
/* positionDiscontinuity= */ false,
|
||||||
|
/* ignored */ DISCONTINUITY_REASON_INTERNAL,
|
||||||
|
/* ignored */ C.TIME_UNSET,
|
||||||
|
/* ignored */ C.INDEX_UNSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -540,11 +550,13 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
internalPlayer.setShuffleOrder(shuffleOrder);
|
internalPlayer.setShuffleOrder(shuffleOrder);
|
||||||
updatePlaybackInfo(
|
updatePlaybackInfo(
|
||||||
newPlaybackInfo,
|
newPlaybackInfo,
|
||||||
/* positionDiscontinuity= */ false,
|
|
||||||
/* ignored */ DISCONTINUITY_REASON_INTERNAL,
|
|
||||||
/* timelineChangeReason= */ TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED,
|
/* timelineChangeReason= */ TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED,
|
||||||
/* ignored */ PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST,
|
/* ignored */ PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST,
|
||||||
/* seekProcessed= */ false);
|
/* seekProcessed= */ false,
|
||||||
|
/* positionDiscontinuity= */ false,
|
||||||
|
/* ignored */ DISCONTINUITY_REASON_INTERNAL,
|
||||||
|
/* ignored */ C.TIME_UNSET,
|
||||||
|
/* ignored */ C.INDEX_UNSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -583,11 +595,13 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
internalPlayer.setPlayWhenReady(playWhenReady, playbackSuppressionReason);
|
internalPlayer.setPlayWhenReady(playWhenReady, playbackSuppressionReason);
|
||||||
updatePlaybackInfo(
|
updatePlaybackInfo(
|
||||||
playbackInfo,
|
playbackInfo,
|
||||||
/* positionDiscontinuity= */ false,
|
|
||||||
/* ignored */ DISCONTINUITY_REASON_INTERNAL,
|
|
||||||
/* ignored */ TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED,
|
/* ignored */ TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED,
|
||||||
playWhenReadyChangeReason,
|
playWhenReadyChangeReason,
|
||||||
/* seekProcessed= */ false);
|
/* seekProcessed= */ false,
|
||||||
|
/* positionDiscontinuity= */ false,
|
||||||
|
/* ignored */ DISCONTINUITY_REASON_INTERNAL,
|
||||||
|
/* ignored */ C.TIME_UNSET,
|
||||||
|
/* ignored */ C.INDEX_UNSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -656,7 +670,8 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
@Player.State
|
@Player.State
|
||||||
int newPlaybackState =
|
int newPlaybackState =
|
||||||
getPlaybackState() == Player.STATE_IDLE ? Player.STATE_IDLE : Player.STATE_BUFFERING;
|
getPlaybackState() == Player.STATE_IDLE ? Player.STATE_IDLE : Player.STATE_BUFFERING;
|
||||||
PlaybackInfo newPlaybackInfo = this.playbackInfo.copyWithPlaybackState(newPlaybackState);
|
int oldMaskingWindowIndex = getCurrentWindowIndex();
|
||||||
|
PlaybackInfo newPlaybackInfo = playbackInfo.copyWithPlaybackState(newPlaybackState);
|
||||||
newPlaybackInfo =
|
newPlaybackInfo =
|
||||||
maskTimelineAndPosition(
|
maskTimelineAndPosition(
|
||||||
newPlaybackInfo,
|
newPlaybackInfo,
|
||||||
|
|
@ -665,11 +680,13 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
internalPlayer.seekTo(timeline, windowIndex, C.msToUs(positionMs));
|
internalPlayer.seekTo(timeline, windowIndex, C.msToUs(positionMs));
|
||||||
updatePlaybackInfo(
|
updatePlaybackInfo(
|
||||||
newPlaybackInfo,
|
newPlaybackInfo,
|
||||||
/* positionDiscontinuity= */ true,
|
|
||||||
/* positionDiscontinuityReason= */ DISCONTINUITY_REASON_SEEK,
|
|
||||||
/* ignored */ TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED,
|
/* ignored */ TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED,
|
||||||
/* ignored */ PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST,
|
/* ignored */ PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST,
|
||||||
/* seekProcessed= */ true);
|
/* seekProcessed= */ true,
|
||||||
|
/* positionDiscontinuity= */ true,
|
||||||
|
/* positionDiscontinuityReason= */ DISCONTINUITY_REASON_SEEK,
|
||||||
|
/* discontinuityWindowStartPositionUs= */ getCurrentPositionUsInternal(newPlaybackInfo),
|
||||||
|
oldMaskingWindowIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -685,11 +702,13 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
internalPlayer.setPlaybackParameters(playbackParameters);
|
internalPlayer.setPlaybackParameters(playbackParameters);
|
||||||
updatePlaybackInfo(
|
updatePlaybackInfo(
|
||||||
newPlaybackInfo,
|
newPlaybackInfo,
|
||||||
/* positionDiscontinuity= */ false,
|
|
||||||
/* ignored */ DISCONTINUITY_REASON_INTERNAL,
|
|
||||||
/* ignored */ TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED,
|
/* ignored */ TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED,
|
||||||
/* ignored */ PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST,
|
/* ignored */ PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST,
|
||||||
/* seekProcessed= */ false);
|
/* seekProcessed= */ false,
|
||||||
|
/* positionDiscontinuity= */ false,
|
||||||
|
/* ignored */ DISCONTINUITY_REASON_INTERNAL,
|
||||||
|
/* ignored */ C.TIME_UNSET,
|
||||||
|
/* ignored */ C.INDEX_UNSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -758,13 +777,17 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
}
|
}
|
||||||
pendingOperationAcks++;
|
pendingOperationAcks++;
|
||||||
internalPlayer.stop();
|
internalPlayer.stop();
|
||||||
|
boolean positionDiscontinuity =
|
||||||
|
playbackInfo.timeline.isEmpty() && !this.playbackInfo.timeline.isEmpty();
|
||||||
updatePlaybackInfo(
|
updatePlaybackInfo(
|
||||||
playbackInfo,
|
playbackInfo,
|
||||||
/* positionDiscontinuity= */ false,
|
|
||||||
/* ignored */ DISCONTINUITY_REASON_INTERNAL,
|
|
||||||
TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED,
|
TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED,
|
||||||
/* ignored */ PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST,
|
/* ignored */ PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST,
|
||||||
/* seekProcessed= */ false);
|
/* seekProcessed= */ false,
|
||||||
|
positionDiscontinuity,
|
||||||
|
DISCONTINUITY_REASON_REMOVE,
|
||||||
|
/* discontinuityWindowStartPositionUs= */ getCurrentPositionUsInternal(playbackInfo),
|
||||||
|
/* ignored */ C.INDEX_UNSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -839,13 +862,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long getCurrentPosition() {
|
public long getCurrentPosition() {
|
||||||
if (playbackInfo.timeline.isEmpty()) {
|
return C.usToMs(getCurrentPositionUsInternal(playbackInfo));
|
||||||
return maskingWindowPositionMs;
|
|
||||||
} else if (playbackInfo.periodId.isAd()) {
|
|
||||||
return C.usToMs(playbackInfo.positionUs);
|
|
||||||
} else {
|
|
||||||
return periodPositionUsToWindowPositionMs(playbackInfo.periodId, playbackInfo.positionUs);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -909,8 +926,9 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
contentBufferedPositionUs = loadingPeriod.durationUs;
|
contentBufferedPositionUs = loadingPeriod.durationUs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return periodPositionUsToWindowPositionMs(
|
return C.usToMs(
|
||||||
playbackInfo.loadingMediaPeriodId, contentBufferedPositionUs);
|
periodPositionUsToWindowPositionUs(
|
||||||
|
playbackInfo.timeline, playbackInfo.loadingMediaPeriodId, contentBufferedPositionUs));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -958,6 +976,17 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private long getCurrentPositionUsInternal(PlaybackInfo playbackInfo) {
|
||||||
|
if (playbackInfo.timeline.isEmpty()) {
|
||||||
|
return C.msToUs(maskingWindowPositionMs);
|
||||||
|
} else if (playbackInfo.periodId.isAd()) {
|
||||||
|
return playbackInfo.positionUs;
|
||||||
|
} else {
|
||||||
|
return periodPositionUsToWindowPositionUs(
|
||||||
|
playbackInfo.timeline, playbackInfo.periodId, playbackInfo.positionUs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private List<MediaSource> createMediaSources(List<MediaItem> mediaItems) {
|
private List<MediaSource> createMediaSources(List<MediaItem> mediaItems) {
|
||||||
List<MediaSource> mediaSources = new ArrayList<>();
|
List<MediaSource> mediaSources = new ArrayList<>();
|
||||||
for (int i = 0; i < mediaItems.size(); i++) {
|
for (int i = 0; i < mediaItems.size(); i++) {
|
||||||
|
|
@ -969,8 +998,8 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
private void handlePlaybackInfo(ExoPlayerImplInternal.PlaybackInfoUpdate playbackInfoUpdate) {
|
private void handlePlaybackInfo(ExoPlayerImplInternal.PlaybackInfoUpdate playbackInfoUpdate) {
|
||||||
pendingOperationAcks -= playbackInfoUpdate.operationAcks;
|
pendingOperationAcks -= playbackInfoUpdate.operationAcks;
|
||||||
if (playbackInfoUpdate.positionDiscontinuity) {
|
if (playbackInfoUpdate.positionDiscontinuity) {
|
||||||
hasPendingDiscontinuity = true;
|
|
||||||
pendingDiscontinuityReason = playbackInfoUpdate.discontinuityReason;
|
pendingDiscontinuityReason = playbackInfoUpdate.discontinuityReason;
|
||||||
|
pendingDiscontinuity = true;
|
||||||
}
|
}
|
||||||
if (playbackInfoUpdate.hasPlayWhenReadyChangeReason) {
|
if (playbackInfoUpdate.hasPlayWhenReadyChangeReason) {
|
||||||
pendingPlayWhenReadyChangeReason = playbackInfoUpdate.playWhenReadyChangeReason;
|
pendingPlayWhenReadyChangeReason = playbackInfoUpdate.playWhenReadyChangeReason;
|
||||||
|
|
@ -991,15 +1020,33 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
mediaSourceHolderSnapshots.get(i).timeline = timelines.get(i);
|
mediaSourceHolderSnapshots.get(i).timeline = timelines.get(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
boolean positionDiscontinuity = hasPendingDiscontinuity;
|
boolean positionDiscontinuity = false;
|
||||||
hasPendingDiscontinuity = false;
|
long discontinuityWindowStartPositionUs = C.TIME_UNSET;
|
||||||
|
if (pendingDiscontinuity) {
|
||||||
|
positionDiscontinuity =
|
||||||
|
!playbackInfoUpdate.playbackInfo.periodId.equals(playbackInfo.periodId)
|
||||||
|
|| playbackInfoUpdate.playbackInfo.discontinuityStartPositionUs
|
||||||
|
!= playbackInfo.positionUs;
|
||||||
|
if (positionDiscontinuity) {
|
||||||
|
discontinuityWindowStartPositionUs =
|
||||||
|
newTimeline.isEmpty() || playbackInfoUpdate.playbackInfo.periodId.isAd()
|
||||||
|
? playbackInfoUpdate.playbackInfo.discontinuityStartPositionUs
|
||||||
|
: periodPositionUsToWindowPositionUs(
|
||||||
|
newTimeline,
|
||||||
|
playbackInfoUpdate.playbackInfo.periodId,
|
||||||
|
playbackInfoUpdate.playbackInfo.discontinuityStartPositionUs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pendingDiscontinuity = false;
|
||||||
updatePlaybackInfo(
|
updatePlaybackInfo(
|
||||||
playbackInfoUpdate.playbackInfo,
|
playbackInfoUpdate.playbackInfo,
|
||||||
positionDiscontinuity,
|
|
||||||
pendingDiscontinuityReason,
|
|
||||||
TIMELINE_CHANGE_REASON_SOURCE_UPDATE,
|
TIMELINE_CHANGE_REASON_SOURCE_UPDATE,
|
||||||
pendingPlayWhenReadyChangeReason,
|
pendingPlayWhenReadyChangeReason,
|
||||||
/* seekProcessed= */ false);
|
/* seekProcessed= */ false,
|
||||||
|
positionDiscontinuity,
|
||||||
|
pendingDiscontinuityReason,
|
||||||
|
discontinuityWindowStartPositionUs,
|
||||||
|
/* ignored */ C.INDEX_UNSET);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1007,11 +1054,14 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
private void updatePlaybackInfo(
|
private void updatePlaybackInfo(
|
||||||
PlaybackInfo playbackInfo,
|
PlaybackInfo playbackInfo,
|
||||||
boolean positionDiscontinuity,
|
|
||||||
@DiscontinuityReason int positionDiscontinuityReason,
|
|
||||||
@TimelineChangeReason int timelineChangeReason,
|
@TimelineChangeReason int timelineChangeReason,
|
||||||
@PlayWhenReadyChangeReason int playWhenReadyChangeReason,
|
@PlayWhenReadyChangeReason int playWhenReadyChangeReason,
|
||||||
boolean seekProcessed) {
|
boolean seekProcessed,
|
||||||
|
boolean positionDiscontinuity,
|
||||||
|
@DiscontinuityReason int positionDiscontinuityReason,
|
||||||
|
long discontinuityWindowStartPositionUs,
|
||||||
|
int oldMaskingWindowIndex) {
|
||||||
|
|
||||||
// Assign playback info immediately such that all getters return the right values, but keep
|
// Assign playback info immediately such that all getters return the right values, but keep
|
||||||
// snapshot of previous and new state so that listener invocations are triggered correctly.
|
// snapshot of previous and new state so that listener invocations are triggered correctly.
|
||||||
PlaybackInfo previousPlaybackInfo = this.playbackInfo;
|
PlaybackInfo previousPlaybackInfo = this.playbackInfo;
|
||||||
|
|
@ -1042,9 +1092,17 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (positionDiscontinuity) {
|
if (positionDiscontinuity) {
|
||||||
|
PositionInfo previousPositionInfo =
|
||||||
|
getPreviousPositionInfo(
|
||||||
|
positionDiscontinuityReason, previousPlaybackInfo, oldMaskingWindowIndex);
|
||||||
|
PositionInfo positionInfo = getPositionInfo(discontinuityWindowStartPositionUs);
|
||||||
listeners.queueEvent(
|
listeners.queueEvent(
|
||||||
Player.EVENT_POSITION_DISCONTINUITY,
|
Player.EVENT_POSITION_DISCONTINUITY,
|
||||||
listener -> listener.onPositionDiscontinuity(positionDiscontinuityReason));
|
listener -> {
|
||||||
|
listener.onPositionDiscontinuity(positionDiscontinuityReason);
|
||||||
|
listener.onPositionDiscontinuity(
|
||||||
|
previousPositionInfo, positionInfo, positionDiscontinuityReason);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
if (mediaItemTransitioned) {
|
if (mediaItemTransitioned) {
|
||||||
@Nullable final MediaItem mediaItem;
|
@Nullable final MediaItem mediaItem;
|
||||||
|
|
@ -1144,6 +1202,93 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private PositionInfo getPreviousPositionInfo(
|
||||||
|
@DiscontinuityReason int positionDiscontinuityReason,
|
||||||
|
PlaybackInfo oldPlaybackInfo,
|
||||||
|
int oldMaskingWindowIndex) {
|
||||||
|
@Nullable Object oldWindowUid = null;
|
||||||
|
@Nullable Object oldPeriodUid = null;
|
||||||
|
int oldWindowIndex = oldMaskingWindowIndex;
|
||||||
|
int oldPeriodIndex = C.INDEX_UNSET;
|
||||||
|
Timeline.Period oldPeriod = new Timeline.Period();
|
||||||
|
if (!oldPlaybackInfo.timeline.isEmpty()) {
|
||||||
|
oldPeriodUid = oldPlaybackInfo.periodId.periodUid;
|
||||||
|
oldPlaybackInfo.timeline.getPeriodByUid(oldPeriodUid, oldPeriod);
|
||||||
|
oldWindowIndex = oldPeriod.windowIndex;
|
||||||
|
oldPeriodIndex = oldPlaybackInfo.timeline.getIndexOfPeriod(oldPeriodUid);
|
||||||
|
oldWindowUid = oldPlaybackInfo.timeline.getWindow(oldWindowIndex, window).uid;
|
||||||
|
}
|
||||||
|
long oldPositionUs;
|
||||||
|
long oldContentPositionUs;
|
||||||
|
if (positionDiscontinuityReason == DISCONTINUITY_REASON_AUTO_TRANSITION) {
|
||||||
|
oldPositionUs = oldPeriod.positionInWindowUs + oldPeriod.durationUs;
|
||||||
|
oldContentPositionUs = oldPositionUs;
|
||||||
|
if (oldPlaybackInfo.periodId.isAd()) {
|
||||||
|
// The old position is the end of the previous ad.
|
||||||
|
oldPositionUs =
|
||||||
|
oldPeriod.getAdDurationUs(
|
||||||
|
oldPlaybackInfo.periodId.adGroupIndex, oldPlaybackInfo.periodId.adIndexInAdGroup);
|
||||||
|
// The ad cue point is stored in the old requested content position.
|
||||||
|
oldContentPositionUs = getRequestedContentPositionUs(oldPlaybackInfo);
|
||||||
|
} else if (oldPlaybackInfo.periodId.nextAdGroupIndex != C.INDEX_UNSET
|
||||||
|
&& playbackInfo.periodId.isAd()) {
|
||||||
|
// If it's a transition from content to an ad in the same window, the old position is the
|
||||||
|
// ad cue point that is the same as current content position.
|
||||||
|
oldPositionUs = getRequestedContentPositionUs(playbackInfo);
|
||||||
|
oldContentPositionUs = oldPositionUs;
|
||||||
|
}
|
||||||
|
} else if (oldPlaybackInfo.periodId.isAd()) {
|
||||||
|
oldPositionUs = oldPlaybackInfo.positionUs;
|
||||||
|
oldContentPositionUs = getRequestedContentPositionUs(oldPlaybackInfo);
|
||||||
|
} else {
|
||||||
|
oldPositionUs = oldPeriod.positionInWindowUs + oldPlaybackInfo.positionUs;
|
||||||
|
oldContentPositionUs = oldPositionUs;
|
||||||
|
}
|
||||||
|
return new PositionInfo(
|
||||||
|
oldWindowUid,
|
||||||
|
oldWindowIndex,
|
||||||
|
oldPeriodUid,
|
||||||
|
oldPeriodIndex,
|
||||||
|
C.usToMs(oldPositionUs),
|
||||||
|
C.usToMs(oldContentPositionUs),
|
||||||
|
oldPlaybackInfo.periodId.adGroupIndex,
|
||||||
|
oldPlaybackInfo.periodId.adIndexInAdGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
private PositionInfo getPositionInfo(long discontinuityWindowStartPositionUs) {
|
||||||
|
@Nullable Object newWindowUid = null;
|
||||||
|
@Nullable Object newPeriodUid = null;
|
||||||
|
int newWindowIndex = getCurrentWindowIndex();
|
||||||
|
int newPeriodIndex = C.INDEX_UNSET;
|
||||||
|
if (!playbackInfo.timeline.isEmpty()) {
|
||||||
|
newPeriodUid = playbackInfo.periodId.periodUid;
|
||||||
|
playbackInfo.timeline.getPeriodByUid(newPeriodUid, period);
|
||||||
|
newPeriodIndex = playbackInfo.timeline.getIndexOfPeriod(newPeriodUid);
|
||||||
|
newWindowUid = playbackInfo.timeline.getWindow(newWindowIndex, window).uid;
|
||||||
|
}
|
||||||
|
long positionMs = C.usToMs(discontinuityWindowStartPositionUs);
|
||||||
|
return new PositionInfo(
|
||||||
|
newWindowUid,
|
||||||
|
newWindowIndex,
|
||||||
|
newPeriodUid,
|
||||||
|
newPeriodIndex,
|
||||||
|
positionMs,
|
||||||
|
/* contentPositionMs= */ playbackInfo.periodId.isAd()
|
||||||
|
? C.usToMs(getRequestedContentPositionUs(playbackInfo))
|
||||||
|
: positionMs,
|
||||||
|
playbackInfo.periodId.adGroupIndex,
|
||||||
|
playbackInfo.periodId.adIndexInAdGroup);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long getRequestedContentPositionUs(PlaybackInfo playbackInfo) {
|
||||||
|
Timeline.Window window = new Timeline.Window();
|
||||||
|
Timeline.Period period = new Timeline.Period();
|
||||||
|
playbackInfo.timeline.getPeriodByUid(playbackInfo.periodId.periodUid, period);
|
||||||
|
return playbackInfo.requestedContentPositionUs == C.TIME_UNSET
|
||||||
|
? playbackInfo.timeline.getWindow(period.windowIndex, window).getDefaultPositionUs()
|
||||||
|
: period.getPositionInWindowUs() + playbackInfo.requestedContentPositionUs;
|
||||||
|
}
|
||||||
|
|
||||||
private Pair<Boolean, Integer> evaluateMediaItemTransitionReason(
|
private Pair<Boolean, Integer> evaluateMediaItemTransitionReason(
|
||||||
PlaybackInfo playbackInfo,
|
PlaybackInfo playbackInfo,
|
||||||
PlaybackInfo oldPlaybackInfo,
|
PlaybackInfo oldPlaybackInfo,
|
||||||
|
|
@ -1169,7 +1314,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
if (!oldWindowUid.equals(newWindowUid)) {
|
if (!oldWindowUid.equals(newWindowUid)) {
|
||||||
@Player.MediaItemTransitionReason int transitionReason;
|
@Player.MediaItemTransitionReason int transitionReason;
|
||||||
if (positionDiscontinuity
|
if (positionDiscontinuity
|
||||||
&& positionDiscontinuityReason == DISCONTINUITY_REASON_PERIOD_TRANSITION) {
|
&& positionDiscontinuityReason == DISCONTINUITY_REASON_AUTO_TRANSITION) {
|
||||||
transitionReason = MEDIA_ITEM_TRANSITION_REASON_AUTO;
|
transitionReason = MEDIA_ITEM_TRANSITION_REASON_AUTO;
|
||||||
} else if (positionDiscontinuity
|
} else if (positionDiscontinuity
|
||||||
&& positionDiscontinuityReason == DISCONTINUITY_REASON_SEEK) {
|
&& positionDiscontinuityReason == DISCONTINUITY_REASON_SEEK) {
|
||||||
|
|
@ -1182,7 +1327,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
}
|
}
|
||||||
return new Pair<>(/* isTransitioning */ true, transitionReason);
|
return new Pair<>(/* isTransitioning */ true, transitionReason);
|
||||||
} else if (positionDiscontinuity
|
} else if (positionDiscontinuity
|
||||||
&& positionDiscontinuityReason == DISCONTINUITY_REASON_PERIOD_TRANSITION
|
&& positionDiscontinuityReason == DISCONTINUITY_REASON_AUTO_TRANSITION
|
||||||
&& newTimeline.getIndexOfPeriod(playbackInfo.periodId.periodUid)
|
&& newTimeline.getIndexOfPeriod(playbackInfo.periodId.periodUid)
|
||||||
== firstPeriodIndexInNewWindow) {
|
== firstPeriodIndexInNewWindow) {
|
||||||
return new Pair<>(/* isTransitioning */ true, MEDIA_ITEM_TRANSITION_REASON_REPEAT);
|
return new Pair<>(/* isTransitioning */ true, MEDIA_ITEM_TRANSITION_REASON_REPEAT);
|
||||||
|
|
@ -1245,13 +1390,18 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
newPlaybackInfo = newPlaybackInfo.copyWithPlaybackState(maskingPlaybackState);
|
newPlaybackInfo = newPlaybackInfo.copyWithPlaybackState(maskingPlaybackState);
|
||||||
internalPlayer.setMediaSources(
|
internalPlayer.setMediaSources(
|
||||||
holders, startWindowIndex, C.msToUs(startPositionMs), shuffleOrder);
|
holders, startWindowIndex, C.msToUs(startPositionMs), shuffleOrder);
|
||||||
|
boolean positionDiscontinuity =
|
||||||
|
!playbackInfo.periodId.periodUid.equals(newPlaybackInfo.periodId.periodUid)
|
||||||
|
&& !playbackInfo.timeline.isEmpty();
|
||||||
updatePlaybackInfo(
|
updatePlaybackInfo(
|
||||||
newPlaybackInfo,
|
newPlaybackInfo,
|
||||||
/* positionDiscontinuity= */ false,
|
|
||||||
/* ignored */ Player.DISCONTINUITY_REASON_INTERNAL,
|
|
||||||
/* timelineChangeReason= */ TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED,
|
/* timelineChangeReason= */ TIMELINE_CHANGE_REASON_PLAYLIST_CHANGED,
|
||||||
/* ignored */ PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST,
|
/* ignored */ PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST,
|
||||||
/* seekProcessed= */ false);
|
/* seekProcessed= */ false,
|
||||||
|
/* positionDiscontinuity= */ positionDiscontinuity,
|
||||||
|
Player.DISCONTINUITY_REASON_REMOVE,
|
||||||
|
/* discontinuityWindowStartPositionUs= */ getCurrentPositionUsInternal(newPlaybackInfo),
|
||||||
|
/* ignored */ C.INDEX_UNSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<MediaSourceList.MediaSourceHolder> addMediaSourceHolders(
|
private List<MediaSourceList.MediaSourceHolder> addMediaSourceHolders(
|
||||||
|
|
@ -1319,11 +1469,13 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
if (timeline.isEmpty()) {
|
if (timeline.isEmpty()) {
|
||||||
// Reset periodId and loadingPeriodId.
|
// Reset periodId and loadingPeriodId.
|
||||||
MediaPeriodId dummyMediaPeriodId = PlaybackInfo.getDummyPeriodForEmptyTimeline();
|
MediaPeriodId dummyMediaPeriodId = PlaybackInfo.getDummyPeriodForEmptyTimeline();
|
||||||
|
long positionUs = C.msToUs(maskingWindowPositionMs);
|
||||||
playbackInfo =
|
playbackInfo =
|
||||||
playbackInfo.copyWithNewPosition(
|
playbackInfo.copyWithNewPosition(
|
||||||
dummyMediaPeriodId,
|
dummyMediaPeriodId,
|
||||||
/* positionUs= */ C.msToUs(maskingWindowPositionMs),
|
positionUs,
|
||||||
/* requestedContentPositionUs= */ C.msToUs(maskingWindowPositionMs),
|
/* requestedContentPositionUs= */ positionUs,
|
||||||
|
/* discontinuityStartPositionUs= */ positionUs,
|
||||||
/* totalBufferedDurationUs= */ 0,
|
/* totalBufferedDurationUs= */ 0,
|
||||||
TrackGroupArray.EMPTY,
|
TrackGroupArray.EMPTY,
|
||||||
emptyTrackSelectorResult,
|
emptyTrackSelectorResult,
|
||||||
|
|
@ -1352,6 +1504,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
newPeriodId,
|
newPeriodId,
|
||||||
/* positionUs= */ newContentPositionUs,
|
/* positionUs= */ newContentPositionUs,
|
||||||
/* requestedContentPositionUs= */ newContentPositionUs,
|
/* requestedContentPositionUs= */ newContentPositionUs,
|
||||||
|
/* discontinuityStartPositionUs= */ newContentPositionUs,
|
||||||
/* totalBufferedDurationUs= */ 0,
|
/* totalBufferedDurationUs= */ 0,
|
||||||
playingPeriodChanged ? TrackGroupArray.EMPTY : playbackInfo.trackGroups,
|
playingPeriodChanged ? TrackGroupArray.EMPTY : playbackInfo.trackGroups,
|
||||||
playingPeriodChanged ? emptyTrackSelectorResult : playbackInfo.trackSelectorResult,
|
playingPeriodChanged ? emptyTrackSelectorResult : playbackInfo.trackSelectorResult,
|
||||||
|
|
@ -1377,6 +1530,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
newPeriodId,
|
newPeriodId,
|
||||||
/* positionUs= */ playbackInfo.positionUs,
|
/* positionUs= */ playbackInfo.positionUs,
|
||||||
/* requestedContentPositionUs= */ playbackInfo.positionUs,
|
/* requestedContentPositionUs= */ playbackInfo.positionUs,
|
||||||
|
playbackInfo.discontinuityStartPositionUs,
|
||||||
/* totalBufferedDurationUs= */ maskedBufferedPositionUs - playbackInfo.positionUs,
|
/* totalBufferedDurationUs= */ maskedBufferedPositionUs - playbackInfo.positionUs,
|
||||||
playbackInfo.trackGroups,
|
playbackInfo.trackGroups,
|
||||||
playbackInfo.trackSelectorResult,
|
playbackInfo.trackSelectorResult,
|
||||||
|
|
@ -1400,6 +1554,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
newPeriodId,
|
newPeriodId,
|
||||||
/* positionUs= */ newContentPositionUs,
|
/* positionUs= */ newContentPositionUs,
|
||||||
/* requestedContentPositionUs= */ newContentPositionUs,
|
/* requestedContentPositionUs= */ newContentPositionUs,
|
||||||
|
/* discontinuityStartPositionUs= */ newContentPositionUs,
|
||||||
maskedTotalBufferedDurationUs,
|
maskedTotalBufferedDurationUs,
|
||||||
playbackInfo.trackGroups,
|
playbackInfo.trackGroups,
|
||||||
playbackInfo.trackSelectorResult,
|
playbackInfo.trackSelectorResult,
|
||||||
|
|
@ -1468,11 +1623,11 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||||
return timeline.getPeriodPosition(window, period, windowIndex, C.msToUs(windowPositionMs));
|
return timeline.getPeriodPosition(window, period, windowIndex, C.msToUs(windowPositionMs));
|
||||||
}
|
}
|
||||||
|
|
||||||
private long periodPositionUsToWindowPositionMs(MediaPeriodId periodId, long positionUs) {
|
private long periodPositionUsToWindowPositionUs(
|
||||||
long positionMs = C.usToMs(positionUs);
|
Timeline timeline, MediaPeriodId periodId, long positionUs) {
|
||||||
playbackInfo.timeline.getPeriodByUid(periodId.periodUid, period);
|
timeline.getPeriodByUid(periodId.periodUid, period);
|
||||||
positionMs += period.getPositionInWindowMs();
|
positionUs += period.getPositionInWindowUs();
|
||||||
return positionMs;
|
return positionUs;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isPlaying(PlaybackInfo playbackInfo) {
|
private static boolean isPlaying(PlaybackInfo playbackInfo) {
|
||||||
|
|
|
||||||
|
|
@ -668,7 +668,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
mediaSourceList.setMediaSources(
|
mediaSourceList.setMediaSources(
|
||||||
mediaSourceListUpdateMessage.mediaSourceHolders,
|
mediaSourceListUpdateMessage.mediaSourceHolders,
|
||||||
mediaSourceListUpdateMessage.shuffleOrder);
|
mediaSourceListUpdateMessage.shuffleOrder);
|
||||||
handleMediaSourceListInfoRefreshed(timeline);
|
handleMediaSourceListInfoRefreshed(timeline, /* isSourceRefresh= */ false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addMediaItemsInternal(MediaSourceListUpdateMessage addMessage, int insertionIndex)
|
private void addMediaItemsInternal(MediaSourceListUpdateMessage addMessage, int insertionIndex)
|
||||||
|
|
@ -679,7 +679,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
insertionIndex == C.INDEX_UNSET ? mediaSourceList.getSize() : insertionIndex,
|
insertionIndex == C.INDEX_UNSET ? mediaSourceList.getSize() : insertionIndex,
|
||||||
addMessage.mediaSourceHolders,
|
addMessage.mediaSourceHolders,
|
||||||
addMessage.shuffleOrder);
|
addMessage.shuffleOrder);
|
||||||
handleMediaSourceListInfoRefreshed(timeline);
|
handleMediaSourceListInfoRefreshed(timeline, /* isSourceRefresh= */ false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void moveMediaItemsInternal(MoveMediaItemsMessage moveMediaItemsMessage)
|
private void moveMediaItemsInternal(MoveMediaItemsMessage moveMediaItemsMessage)
|
||||||
|
|
@ -691,24 +691,25 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
moveMediaItemsMessage.toIndex,
|
moveMediaItemsMessage.toIndex,
|
||||||
moveMediaItemsMessage.newFromIndex,
|
moveMediaItemsMessage.newFromIndex,
|
||||||
moveMediaItemsMessage.shuffleOrder);
|
moveMediaItemsMessage.shuffleOrder);
|
||||||
handleMediaSourceListInfoRefreshed(timeline);
|
handleMediaSourceListInfoRefreshed(timeline, /* isSourceRefresh= */ false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeMediaItemsInternal(int fromIndex, int toIndex, ShuffleOrder shuffleOrder)
|
private void removeMediaItemsInternal(int fromIndex, int toIndex, ShuffleOrder shuffleOrder)
|
||||||
throws ExoPlaybackException {
|
throws ExoPlaybackException {
|
||||||
playbackInfoUpdate.incrementPendingOperationAcks(/* operationAcks= */ 1);
|
playbackInfoUpdate.incrementPendingOperationAcks(/* operationAcks= */ 1);
|
||||||
Timeline timeline = mediaSourceList.removeMediaSourceRange(fromIndex, toIndex, shuffleOrder);
|
Timeline timeline = mediaSourceList.removeMediaSourceRange(fromIndex, toIndex, shuffleOrder);
|
||||||
handleMediaSourceListInfoRefreshed(timeline);
|
handleMediaSourceListInfoRefreshed(timeline, /* isSourceRefresh= */ false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void mediaSourceListUpdateRequestedInternal() throws ExoPlaybackException {
|
private void mediaSourceListUpdateRequestedInternal() throws ExoPlaybackException {
|
||||||
handleMediaSourceListInfoRefreshed(mediaSourceList.createTimeline());
|
handleMediaSourceListInfoRefreshed(
|
||||||
|
mediaSourceList.createTimeline(), /* isSourceRefresh= */ true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setShuffleOrderInternal(ShuffleOrder shuffleOrder) throws ExoPlaybackException {
|
private void setShuffleOrderInternal(ShuffleOrder shuffleOrder) throws ExoPlaybackException {
|
||||||
playbackInfoUpdate.incrementPendingOperationAcks(/* operationAcks= */ 1);
|
playbackInfoUpdate.incrementPendingOperationAcks(/* operationAcks= */ 1);
|
||||||
Timeline timeline = mediaSourceList.setShuffleOrder(shuffleOrder);
|
Timeline timeline = mediaSourceList.setShuffleOrder(shuffleOrder);
|
||||||
handleMediaSourceListInfoRefreshed(timeline);
|
handleMediaSourceListInfoRefreshed(timeline, /* isSourceRefresh= */ false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void notifyTrackSelectionPlayWhenReadyChanged(boolean playWhenReady) {
|
private void notifyTrackSelectionPlayWhenReadyChanged(boolean playWhenReady) {
|
||||||
|
|
@ -803,10 +804,12 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
if (newPositionUs != playbackInfo.positionUs) {
|
if (newPositionUs != playbackInfo.positionUs) {
|
||||||
playbackInfo =
|
playbackInfo =
|
||||||
handlePositionDiscontinuity(
|
handlePositionDiscontinuity(
|
||||||
periodId, newPositionUs, playbackInfo.requestedContentPositionUs);
|
periodId,
|
||||||
if (sendDiscontinuity) {
|
newPositionUs,
|
||||||
playbackInfoUpdate.setPositionDiscontinuity(Player.DISCONTINUITY_REASON_INTERNAL);
|
playbackInfo.requestedContentPositionUs,
|
||||||
}
|
playbackInfo.discontinuityStartPositionUs,
|
||||||
|
sendDiscontinuity,
|
||||||
|
Player.DISCONTINUITY_REASON_INTERNAL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -852,9 +855,11 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
playbackInfo =
|
playbackInfo =
|
||||||
handlePositionDiscontinuity(
|
handlePositionDiscontinuity(
|
||||||
playbackInfo.periodId,
|
playbackInfo.periodId,
|
||||||
discontinuityPositionUs,
|
/* positionUs= */ discontinuityPositionUs,
|
||||||
playbackInfo.requestedContentPositionUs);
|
playbackInfo.requestedContentPositionUs,
|
||||||
playbackInfoUpdate.setPositionDiscontinuity(Player.DISCONTINUITY_REASON_INTERNAL);
|
/* discontinuityStartPositionUs= */ discontinuityPositionUs,
|
||||||
|
/* reportDiscontinuity= */ true,
|
||||||
|
Player.DISCONTINUITY_REASON_INTERNAL);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
rendererPositionUs =
|
rendererPositionUs =
|
||||||
|
|
@ -1166,10 +1171,13 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
playbackInfo =
|
playbackInfo =
|
||||||
handlePositionDiscontinuity(periodId, periodPositionUs, requestedContentPositionUs);
|
handlePositionDiscontinuity(
|
||||||
if (seekPositionAdjusted) {
|
periodId,
|
||||||
playbackInfoUpdate.setPositionDiscontinuity(Player.DISCONTINUITY_REASON_SEEK_ADJUSTMENT);
|
periodPositionUs,
|
||||||
}
|
requestedContentPositionUs,
|
||||||
|
/* discontinuityStartPositionUs= */ periodPositionUs,
|
||||||
|
/* reportDiscontinuity= */ seekPositionAdjusted,
|
||||||
|
Player.DISCONTINUITY_REASON_SEEK_ADJUSTMENT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1385,6 +1393,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
playbackInfo.timeline,
|
playbackInfo.timeline,
|
||||||
mediaPeriodId,
|
mediaPeriodId,
|
||||||
requestedContentPositionUs,
|
requestedContentPositionUs,
|
||||||
|
/* discontinuityStartPositionUs= */ startPositionUs,
|
||||||
playbackInfo.playbackState,
|
playbackInfo.playbackState,
|
||||||
resetError ? null : playbackInfo.playbackError,
|
resetError ? null : playbackInfo.playbackError,
|
||||||
/* isLoading= */ false,
|
/* isLoading= */ false,
|
||||||
|
|
@ -1395,9 +1404,9 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
playbackInfo.playWhenReady,
|
playbackInfo.playWhenReady,
|
||||||
playbackInfo.playbackSuppressionReason,
|
playbackInfo.playbackSuppressionReason,
|
||||||
playbackInfo.playbackParameters,
|
playbackInfo.playbackParameters,
|
||||||
startPositionUs,
|
/* bufferedPositionUs= */ startPositionUs,
|
||||||
/* totalBufferedDurationUs= */ 0,
|
/* totalBufferedDurationUs= */ 0,
|
||||||
startPositionUs,
|
/* positionUs= */ startPositionUs,
|
||||||
offloadSchedulingEnabled,
|
offloadSchedulingEnabled,
|
||||||
/* sleepingForOffload= */ false);
|
/* sleepingForOffload= */ false);
|
||||||
if (releaseMediaSourceList) {
|
if (releaseMediaSourceList) {
|
||||||
|
|
@ -1634,12 +1643,18 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
long periodPositionUs =
|
long periodPositionUs =
|
||||||
playingPeriodHolder.applyTrackSelection(
|
playingPeriodHolder.applyTrackSelection(
|
||||||
newTrackSelectorResult, playbackInfo.positionUs, recreateStreams, streamResetFlags);
|
newTrackSelectorResult, playbackInfo.positionUs, recreateStreams, streamResetFlags);
|
||||||
|
boolean hasDiscontinuity =
|
||||||
|
playbackInfo.playbackState != Player.STATE_ENDED
|
||||||
|
&& periodPositionUs != playbackInfo.positionUs;
|
||||||
playbackInfo =
|
playbackInfo =
|
||||||
handlePositionDiscontinuity(
|
handlePositionDiscontinuity(
|
||||||
playbackInfo.periodId, periodPositionUs, playbackInfo.requestedContentPositionUs);
|
playbackInfo.periodId,
|
||||||
if (playbackInfo.playbackState != Player.STATE_ENDED
|
periodPositionUs,
|
||||||
&& periodPositionUs != playbackInfo.positionUs) {
|
playbackInfo.requestedContentPositionUs,
|
||||||
playbackInfoUpdate.setPositionDiscontinuity(Player.DISCONTINUITY_REASON_INTERNAL);
|
playbackInfo.discontinuityStartPositionUs,
|
||||||
|
hasDiscontinuity,
|
||||||
|
Player.DISCONTINUITY_REASON_INTERNAL);
|
||||||
|
if (hasDiscontinuity) {
|
||||||
resetRendererPosition(periodPositionUs);
|
resetRendererPosition(periodPositionUs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1742,7 +1757,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|| !shouldPlayWhenReady());
|
|| !shouldPlayWhenReady());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleMediaSourceListInfoRefreshed(Timeline timeline) throws ExoPlaybackException {
|
private void handleMediaSourceListInfoRefreshed(Timeline timeline, boolean isSourceRefresh)
|
||||||
|
throws ExoPlaybackException {
|
||||||
PositionUpdateForPlaylistChange positionUpdate =
|
PositionUpdateForPlaylistChange positionUpdate =
|
||||||
resolvePositionForPlaylistChange(
|
resolvePositionForPlaylistChange(
|
||||||
timeline,
|
timeline,
|
||||||
|
|
@ -1759,7 +1775,6 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
long newPositionUs = positionUpdate.periodPositionUs;
|
long newPositionUs = positionUpdate.periodPositionUs;
|
||||||
boolean periodPositionChanged =
|
boolean periodPositionChanged =
|
||||||
!playbackInfo.periodId.equals(newPeriodId) || newPositionUs != playbackInfo.positionUs;
|
!playbackInfo.periodId.equals(newPeriodId) || newPositionUs != playbackInfo.positionUs;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (positionUpdate.endPlayback) {
|
if (positionUpdate.endPlayback) {
|
||||||
if (playbackInfo.playbackState != Player.STATE_IDLE) {
|
if (playbackInfo.playbackState != Player.STATE_IDLE) {
|
||||||
|
|
@ -1800,8 +1815,25 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
: C.TIME_UNSET);
|
: C.TIME_UNSET);
|
||||||
if (periodPositionChanged
|
if (periodPositionChanged
|
||||||
|| newRequestedContentPositionUs != playbackInfo.requestedContentPositionUs) {
|
|| newRequestedContentPositionUs != playbackInfo.requestedContentPositionUs) {
|
||||||
|
Object oldPeriodUid = playbackInfo.periodId.periodUid;
|
||||||
|
Timeline oldTimeline = playbackInfo.timeline;
|
||||||
|
boolean reportDiscontinuity =
|
||||||
|
periodPositionChanged
|
||||||
|
&& isSourceRefresh
|
||||||
|
&& !oldTimeline.isEmpty()
|
||||||
|
&& !oldTimeline.getWindow(
|
||||||
|
oldTimeline.getPeriodByUid(oldPeriodUid, period).windowIndex, window)
|
||||||
|
.isPlaceholder;
|
||||||
playbackInfo =
|
playbackInfo =
|
||||||
handlePositionDiscontinuity(newPeriodId, newPositionUs, newRequestedContentPositionUs);
|
handlePositionDiscontinuity(
|
||||||
|
newPeriodId,
|
||||||
|
newPositionUs,
|
||||||
|
newRequestedContentPositionUs,
|
||||||
|
playbackInfo.discontinuityStartPositionUs,
|
||||||
|
reportDiscontinuity,
|
||||||
|
timeline.getIndexOfPeriod(oldPeriodUid) == C.INDEX_UNSET
|
||||||
|
? Player.DISCONTINUITY_REASON_REMOVE
|
||||||
|
: Player.DISCONTINUITY_REASON_SKIP);
|
||||||
}
|
}
|
||||||
resetPendingPauseAtEndOfPeriod();
|
resetPendingPauseAtEndOfPeriod();
|
||||||
resolvePendingMessagePositions(
|
resolvePendingMessagePositions(
|
||||||
|
|
@ -2049,12 +2081,10 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
handlePositionDiscontinuity(
|
handlePositionDiscontinuity(
|
||||||
newPlayingPeriodHolder.info.id,
|
newPlayingPeriodHolder.info.id,
|
||||||
newPlayingPeriodHolder.info.startPositionUs,
|
newPlayingPeriodHolder.info.startPositionUs,
|
||||||
newPlayingPeriodHolder.info.requestedContentPositionUs);
|
newPlayingPeriodHolder.info.requestedContentPositionUs,
|
||||||
int discontinuityReason =
|
/* discontinuityStartPositionUs= */ newPlayingPeriodHolder.info.startPositionUs,
|
||||||
oldPlayingPeriodHolder.info.isLastInTimelinePeriod
|
/* reportDiscontinuity= */ true,
|
||||||
? Player.DISCONTINUITY_REASON_PERIOD_TRANSITION
|
Player.DISCONTINUITY_REASON_AUTO_TRANSITION);
|
||||||
: Player.DISCONTINUITY_REASON_AD_INSERTION;
|
|
||||||
playbackInfoUpdate.setPositionDiscontinuity(discontinuityReason);
|
|
||||||
updateLivePlaybackSpeedControl(
|
updateLivePlaybackSpeedControl(
|
||||||
/* newTimeline= */ playbackInfo.timeline,
|
/* newTimeline= */ playbackInfo.timeline,
|
||||||
/* newPeriodId= */ newPlayingPeriodHolder.info.id,
|
/* newPeriodId= */ newPlayingPeriodHolder.info.id,
|
||||||
|
|
@ -2140,7 +2170,10 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
handlePositionDiscontinuity(
|
handlePositionDiscontinuity(
|
||||||
playbackInfo.periodId,
|
playbackInfo.periodId,
|
||||||
loadingPeriodHolder.info.startPositionUs,
|
loadingPeriodHolder.info.startPositionUs,
|
||||||
playbackInfo.requestedContentPositionUs);
|
playbackInfo.requestedContentPositionUs,
|
||||||
|
loadingPeriodHolder.info.startPositionUs,
|
||||||
|
/* reportDiscontinuity= */ false,
|
||||||
|
/* ignored */ Player.DISCONTINUITY_REASON_INTERNAL);
|
||||||
}
|
}
|
||||||
maybeContinueLoading();
|
maybeContinueLoading();
|
||||||
}
|
}
|
||||||
|
|
@ -2232,7 +2265,12 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
|
||||||
@CheckResult
|
@CheckResult
|
||||||
private PlaybackInfo handlePositionDiscontinuity(
|
private PlaybackInfo handlePositionDiscontinuity(
|
||||||
MediaPeriodId mediaPeriodId, long positionUs, long contentPositionUs) {
|
MediaPeriodId mediaPeriodId,
|
||||||
|
long positionUs,
|
||||||
|
long contentPositionUs,
|
||||||
|
long discontinuityStartPositionUs,
|
||||||
|
boolean reportDiscontinuity,
|
||||||
|
@DiscontinuityReason int discontinuityReason) {
|
||||||
deliverPendingMessageAtStartPositionRequired =
|
deliverPendingMessageAtStartPositionRequired =
|
||||||
deliverPendingMessageAtStartPositionRequired
|
deliverPendingMessageAtStartPositionRequired
|
||||||
|| positionUs != playbackInfo.positionUs
|
|| positionUs != playbackInfo.positionUs
|
||||||
|
|
@ -2264,11 +2302,14 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
trackSelectorResult = emptyTrackSelectorResult;
|
trackSelectorResult = emptyTrackSelectorResult;
|
||||||
staticMetadata = ImmutableList.of();
|
staticMetadata = ImmutableList.of();
|
||||||
}
|
}
|
||||||
|
if (reportDiscontinuity) {
|
||||||
|
playbackInfoUpdate.setPositionDiscontinuity(discontinuityReason);
|
||||||
|
}
|
||||||
return playbackInfo.copyWithNewPosition(
|
return playbackInfo.copyWithNewPosition(
|
||||||
mediaPeriodId,
|
mediaPeriodId,
|
||||||
positionUs,
|
positionUs,
|
||||||
contentPositionUs,
|
contentPositionUs,
|
||||||
|
discontinuityStartPositionUs,
|
||||||
getTotalBufferedDurationUs(),
|
getTotalBufferedDurationUs(),
|
||||||
trackGroupArray,
|
trackGroupArray,
|
||||||
trackSelectorResult,
|
trackSelectorResult,
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,8 @@ import java.util.List;
|
||||||
* suspended content.
|
* suspended content.
|
||||||
*/
|
*/
|
||||||
public final long requestedContentPositionUs;
|
public final long requestedContentPositionUs;
|
||||||
|
/** The start position after a reported position discontinuity, in microseconds. */
|
||||||
|
public final long discontinuityStartPositionUs;
|
||||||
/** The current playback state. One of the {@link Player}.STATE_ constants. */
|
/** The current playback state. One of the {@link Player}.STATE_ constants. */
|
||||||
@Player.State public final int playbackState;
|
@Player.State public final int playbackState;
|
||||||
/** The current playback error, or null if this is not an error state. */
|
/** The current playback error, or null if this is not an error state. */
|
||||||
|
|
@ -104,6 +106,7 @@ import java.util.List;
|
||||||
Timeline.EMPTY,
|
Timeline.EMPTY,
|
||||||
PLACEHOLDER_MEDIA_PERIOD_ID,
|
PLACEHOLDER_MEDIA_PERIOD_ID,
|
||||||
/* requestedContentPositionUs= */ C.TIME_UNSET,
|
/* requestedContentPositionUs= */ C.TIME_UNSET,
|
||||||
|
/* discontinuityStartPositionUs= */ 0,
|
||||||
Player.STATE_IDLE,
|
Player.STATE_IDLE,
|
||||||
/* playbackError= */ null,
|
/* playbackError= */ null,
|
||||||
/* isLoading= */ false,
|
/* isLoading= */ false,
|
||||||
|
|
@ -147,6 +150,7 @@ import java.util.List;
|
||||||
Timeline timeline,
|
Timeline timeline,
|
||||||
MediaPeriodId periodId,
|
MediaPeriodId periodId,
|
||||||
long requestedContentPositionUs,
|
long requestedContentPositionUs,
|
||||||
|
long discontinuityStartPositionUs,
|
||||||
@Player.State int playbackState,
|
@Player.State int playbackState,
|
||||||
@Nullable ExoPlaybackException playbackError,
|
@Nullable ExoPlaybackException playbackError,
|
||||||
boolean isLoading,
|
boolean isLoading,
|
||||||
|
|
@ -165,6 +169,7 @@ import java.util.List;
|
||||||
this.timeline = timeline;
|
this.timeline = timeline;
|
||||||
this.periodId = periodId;
|
this.periodId = periodId;
|
||||||
this.requestedContentPositionUs = requestedContentPositionUs;
|
this.requestedContentPositionUs = requestedContentPositionUs;
|
||||||
|
this.discontinuityStartPositionUs = discontinuityStartPositionUs;
|
||||||
this.playbackState = playbackState;
|
this.playbackState = playbackState;
|
||||||
this.playbackError = playbackError;
|
this.playbackError = playbackError;
|
||||||
this.isLoading = isLoading;
|
this.isLoading = isLoading;
|
||||||
|
|
@ -207,6 +212,7 @@ import java.util.List;
|
||||||
MediaPeriodId periodId,
|
MediaPeriodId periodId,
|
||||||
long positionUs,
|
long positionUs,
|
||||||
long requestedContentPositionUs,
|
long requestedContentPositionUs,
|
||||||
|
long discontinuityStartPositionUs,
|
||||||
long totalBufferedDurationUs,
|
long totalBufferedDurationUs,
|
||||||
TrackGroupArray trackGroups,
|
TrackGroupArray trackGroups,
|
||||||
TrackSelectorResult trackSelectorResult,
|
TrackSelectorResult trackSelectorResult,
|
||||||
|
|
@ -215,6 +221,7 @@ import java.util.List;
|
||||||
timeline,
|
timeline,
|
||||||
periodId,
|
periodId,
|
||||||
requestedContentPositionUs,
|
requestedContentPositionUs,
|
||||||
|
discontinuityStartPositionUs,
|
||||||
playbackState,
|
playbackState,
|
||||||
playbackError,
|
playbackError,
|
||||||
isLoading,
|
isLoading,
|
||||||
|
|
@ -244,6 +251,7 @@ import java.util.List;
|
||||||
timeline,
|
timeline,
|
||||||
periodId,
|
periodId,
|
||||||
requestedContentPositionUs,
|
requestedContentPositionUs,
|
||||||
|
discontinuityStartPositionUs,
|
||||||
playbackState,
|
playbackState,
|
||||||
playbackError,
|
playbackError,
|
||||||
isLoading,
|
isLoading,
|
||||||
|
|
@ -273,6 +281,7 @@ import java.util.List;
|
||||||
timeline,
|
timeline,
|
||||||
periodId,
|
periodId,
|
||||||
requestedContentPositionUs,
|
requestedContentPositionUs,
|
||||||
|
discontinuityStartPositionUs,
|
||||||
playbackState,
|
playbackState,
|
||||||
playbackError,
|
playbackError,
|
||||||
isLoading,
|
isLoading,
|
||||||
|
|
@ -302,6 +311,7 @@ import java.util.List;
|
||||||
timeline,
|
timeline,
|
||||||
periodId,
|
periodId,
|
||||||
requestedContentPositionUs,
|
requestedContentPositionUs,
|
||||||
|
discontinuityStartPositionUs,
|
||||||
playbackState,
|
playbackState,
|
||||||
playbackError,
|
playbackError,
|
||||||
isLoading,
|
isLoading,
|
||||||
|
|
@ -331,6 +341,7 @@ import java.util.List;
|
||||||
timeline,
|
timeline,
|
||||||
periodId,
|
periodId,
|
||||||
requestedContentPositionUs,
|
requestedContentPositionUs,
|
||||||
|
discontinuityStartPositionUs,
|
||||||
playbackState,
|
playbackState,
|
||||||
playbackError,
|
playbackError,
|
||||||
isLoading,
|
isLoading,
|
||||||
|
|
@ -360,6 +371,7 @@ import java.util.List;
|
||||||
timeline,
|
timeline,
|
||||||
periodId,
|
periodId,
|
||||||
requestedContentPositionUs,
|
requestedContentPositionUs,
|
||||||
|
discontinuityStartPositionUs,
|
||||||
playbackState,
|
playbackState,
|
||||||
playbackError,
|
playbackError,
|
||||||
isLoading,
|
isLoading,
|
||||||
|
|
@ -393,6 +405,7 @@ import java.util.List;
|
||||||
timeline,
|
timeline,
|
||||||
periodId,
|
periodId,
|
||||||
requestedContentPositionUs,
|
requestedContentPositionUs,
|
||||||
|
discontinuityStartPositionUs,
|
||||||
playbackState,
|
playbackState,
|
||||||
playbackError,
|
playbackError,
|
||||||
isLoading,
|
isLoading,
|
||||||
|
|
@ -422,6 +435,7 @@ import java.util.List;
|
||||||
timeline,
|
timeline,
|
||||||
periodId,
|
periodId,
|
||||||
requestedContentPositionUs,
|
requestedContentPositionUs,
|
||||||
|
discontinuityStartPositionUs,
|
||||||
playbackState,
|
playbackState,
|
||||||
playbackError,
|
playbackError,
|
||||||
isLoading,
|
isLoading,
|
||||||
|
|
@ -452,6 +466,7 @@ import java.util.List;
|
||||||
timeline,
|
timeline,
|
||||||
periodId,
|
periodId,
|
||||||
requestedContentPositionUs,
|
requestedContentPositionUs,
|
||||||
|
discontinuityStartPositionUs,
|
||||||
playbackState,
|
playbackState,
|
||||||
playbackError,
|
playbackError,
|
||||||
isLoading,
|
isLoading,
|
||||||
|
|
@ -481,6 +496,7 @@ import java.util.List;
|
||||||
timeline,
|
timeline,
|
||||||
periodId,
|
periodId,
|
||||||
requestedContentPositionUs,
|
requestedContentPositionUs,
|
||||||
|
discontinuityStartPositionUs,
|
||||||
playbackState,
|
playbackState,
|
||||||
playbackError,
|
playbackError,
|
||||||
isLoading,
|
isLoading,
|
||||||
|
|
|
||||||
|
|
@ -706,8 +706,13 @@ public class AnalyticsCollector
|
||||||
listener -> listener.onPlayerError(eventTime, error));
|
listener -> listener.onPlayerError(eventTime, error));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calling deprecated callback.
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
@Override
|
@Override
|
||||||
public final void onPositionDiscontinuity(@Player.DiscontinuityReason int reason) {
|
public final void onPositionDiscontinuity(
|
||||||
|
Player.PositionInfo oldPosition,
|
||||||
|
Player.PositionInfo newPosition,
|
||||||
|
@Player.DiscontinuityReason int reason) {
|
||||||
if (reason == Player.DISCONTINUITY_REASON_SEEK) {
|
if (reason == Player.DISCONTINUITY_REASON_SEEK) {
|
||||||
isSeeking = false;
|
isSeeking = false;
|
||||||
}
|
}
|
||||||
|
|
@ -716,7 +721,10 @@ public class AnalyticsCollector
|
||||||
sendEvent(
|
sendEvent(
|
||||||
eventTime,
|
eventTime,
|
||||||
AnalyticsListener.EVENT_POSITION_DISCONTINUITY,
|
AnalyticsListener.EVENT_POSITION_DISCONTINUITY,
|
||||||
listener -> listener.onPositionDiscontinuity(eventTime, reason));
|
listener -> {
|
||||||
|
listener.onPositionDiscontinuity(eventTime, reason);
|
||||||
|
listener.onPositionDiscontinuity(eventTime, oldPosition, newPosition, reason);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -236,7 +236,7 @@ public interface AnalyticsListener {
|
||||||
int EVENT_PLAYER_ERROR = Player.EVENT_PLAYER_ERROR;
|
int EVENT_PLAYER_ERROR = Player.EVENT_PLAYER_ERROR;
|
||||||
/**
|
/**
|
||||||
* A position discontinuity occurred. See {@link
|
* A position discontinuity occurred. See {@link
|
||||||
* Player.EventListener#onPositionDiscontinuity(int)}.
|
* Player.EventListener#onPositionDiscontinuity(Player.PositionInfo, Player.PositionInfo, int)}.
|
||||||
*/
|
*/
|
||||||
int EVENT_POSITION_DISCONTINUITY = Player.EVENT_POSITION_DISCONTINUITY;
|
int EVENT_POSITION_DISCONTINUITY = Player.EVENT_POSITION_DISCONTINUITY;
|
||||||
/** {@link Player#getPlaybackParameters()} changed. */
|
/** {@link Player#getPlaybackParameters()} changed. */
|
||||||
|
|
@ -531,13 +531,26 @@ public interface AnalyticsListener {
|
||||||
@Nullable MediaItem mediaItem,
|
@Nullable MediaItem mediaItem,
|
||||||
@Player.MediaItemTransitionReason int reason) {}
|
@Player.MediaItemTransitionReason int reason) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use {@link #onPositionDiscontinuity(EventTime, Player.PositionInfo,
|
||||||
|
* Player.PositionInfo, int)} instead.
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
default void onPositionDiscontinuity(EventTime eventTime, @DiscontinuityReason int reason) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when a position discontinuity occurred.
|
* Called when a position discontinuity occurred.
|
||||||
*
|
*
|
||||||
* @param eventTime The event time.
|
* @param eventTime The event time.
|
||||||
|
* @param oldPosition The position before the discontinuity.
|
||||||
|
* @param newPosition The position after the discontinuity.
|
||||||
* @param reason The reason for the position discontinuity.
|
* @param reason The reason for the position discontinuity.
|
||||||
*/
|
*/
|
||||||
default void onPositionDiscontinuity(EventTime eventTime, @DiscontinuityReason int reason) {}
|
default void onPositionDiscontinuity(
|
||||||
|
EventTime eventTime,
|
||||||
|
Player.PositionInfo oldPosition,
|
||||||
|
Player.PositionInfo newPosition,
|
||||||
|
@DiscontinuityReason int reason) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when a seek operation started.
|
* Called when a seek operation started.
|
||||||
|
|
|
||||||
|
|
@ -191,9 +191,7 @@ public final class DefaultPlaybackSessionManager implements PlaybackSessionManag
|
||||||
public synchronized void updateSessionsWithDiscontinuity(
|
public synchronized void updateSessionsWithDiscontinuity(
|
||||||
EventTime eventTime, @DiscontinuityReason int reason) {
|
EventTime eventTime, @DiscontinuityReason int reason) {
|
||||||
Assertions.checkNotNull(listener);
|
Assertions.checkNotNull(listener);
|
||||||
boolean hasAutomaticTransition =
|
boolean hasAutomaticTransition = reason == Player.DISCONTINUITY_REASON_AUTO_TRANSITION;
|
||||||
reason == Player.DISCONTINUITY_REASON_PERIOD_TRANSITION
|
|
||||||
|| reason == Player.DISCONTINUITY_REASON_AD_INSERTION;
|
|
||||||
Iterator<SessionDescriptor> iterator = sessions.values().iterator();
|
Iterator<SessionDescriptor> iterator = sessions.values().iterator();
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
SessionDescriptor session = iterator.next();
|
SessionDescriptor session = iterator.next();
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,10 @@ public class DebugTextViewHelper implements Player.EventListener, Runnable {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void onPositionDiscontinuity(@Player.DiscontinuityReason int reason) {
|
public final void onPositionDiscontinuity(
|
||||||
|
Player.PositionInfo oldPosition,
|
||||||
|
Player.PositionInfo newPosition,
|
||||||
|
@Player.DiscontinuityReason int reason) {
|
||||||
updateAndPost();
|
updateAndPost();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -141,8 +141,50 @@ public class EventLogger implements AnalyticsListener {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPositionDiscontinuity(EventTime eventTime, @Player.DiscontinuityReason int reason) {
|
public void onPositionDiscontinuity(
|
||||||
logd(eventTime, "positionDiscontinuity", getDiscontinuityReasonString(reason));
|
EventTime eventTime,
|
||||||
|
Player.PositionInfo oldPosition,
|
||||||
|
Player.PositionInfo newPosition,
|
||||||
|
@Player.DiscontinuityReason int reason) {
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
builder
|
||||||
|
.append("reason=")
|
||||||
|
.append(getDiscontinuityReasonString(reason))
|
||||||
|
.append(", PositionInfo:old [")
|
||||||
|
.append("window=")
|
||||||
|
.append(oldPosition.windowIndex)
|
||||||
|
.append(", period=")
|
||||||
|
.append(oldPosition.periodIndex)
|
||||||
|
.append(", pos=")
|
||||||
|
.append(oldPosition.positionMs);
|
||||||
|
if (oldPosition.adGroupIndex != C.INDEX_UNSET) {
|
||||||
|
builder
|
||||||
|
.append(", contentPos=")
|
||||||
|
.append(oldPosition.contentPositionMs)
|
||||||
|
.append(", adGroup=")
|
||||||
|
.append(oldPosition.adGroupIndex)
|
||||||
|
.append(", ad=")
|
||||||
|
.append(oldPosition.adIndexInAdGroup);
|
||||||
|
}
|
||||||
|
builder
|
||||||
|
.append("], PositionInfo:new [")
|
||||||
|
.append("window=")
|
||||||
|
.append(newPosition.windowIndex)
|
||||||
|
.append(", period=")
|
||||||
|
.append(newPosition.periodIndex)
|
||||||
|
.append(", pos=")
|
||||||
|
.append(newPosition.positionMs);
|
||||||
|
if (newPosition.adGroupIndex != C.INDEX_UNSET) {
|
||||||
|
builder
|
||||||
|
.append(", contentPos=")
|
||||||
|
.append(newPosition.contentPositionMs)
|
||||||
|
.append(", adGroup=")
|
||||||
|
.append(newPosition.adGroupIndex)
|
||||||
|
.append(", ad=")
|
||||||
|
.append(newPosition.adIndexInAdGroup);
|
||||||
|
}
|
||||||
|
builder.append("]");
|
||||||
|
logd(eventTime, "positionDiscontinuity", builder.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -658,14 +700,16 @@ public class EventLogger implements AnalyticsListener {
|
||||||
|
|
||||||
private static String getDiscontinuityReasonString(@Player.DiscontinuityReason int reason) {
|
private static String getDiscontinuityReasonString(@Player.DiscontinuityReason int reason) {
|
||||||
switch (reason) {
|
switch (reason) {
|
||||||
case Player.DISCONTINUITY_REASON_PERIOD_TRANSITION:
|
case Player.DISCONTINUITY_REASON_AUTO_TRANSITION:
|
||||||
return "PERIOD_TRANSITION";
|
return "AUTO_TRANSITION";
|
||||||
case Player.DISCONTINUITY_REASON_SEEK:
|
case Player.DISCONTINUITY_REASON_SEEK:
|
||||||
return "SEEK";
|
return "SEEK";
|
||||||
case Player.DISCONTINUITY_REASON_SEEK_ADJUSTMENT:
|
case Player.DISCONTINUITY_REASON_SEEK_ADJUSTMENT:
|
||||||
return "SEEK_ADJUSTMENT";
|
return "SEEK_ADJUSTMENT";
|
||||||
case Player.DISCONTINUITY_REASON_AD_INSERTION:
|
case Player.DISCONTINUITY_REASON_REMOVE:
|
||||||
return "AD_INSERTION";
|
return "REMOVE";
|
||||||
|
case Player.DISCONTINUITY_REASON_SKIP:
|
||||||
|
return "SKIP";
|
||||||
case Player.DISCONTINUITY_REASON_INTERNAL:
|
case Player.DISCONTINUITY_REASON_INTERNAL:
|
||||||
return "INTERNAL";
|
return "INTERNAL";
|
||||||
default:
|
default:
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -430,6 +430,7 @@ public final class MediaPeriodQueueTest {
|
||||||
mediaPeriodQueue.resolveMediaPeriodIdForAds(
|
mediaPeriodQueue.resolveMediaPeriodIdForAds(
|
||||||
playlistTimeline, firstPeriodUid, /* positionUs= */ 0),
|
playlistTimeline, firstPeriodUid, /* positionUs= */ 0),
|
||||||
/* requestedContentPositionUs= */ C.TIME_UNSET,
|
/* requestedContentPositionUs= */ C.TIME_UNSET,
|
||||||
|
/* discontinuityStartPositionUs= */ 0,
|
||||||
Player.STATE_READY,
|
Player.STATE_READY,
|
||||||
/* playbackError= */ null,
|
/* playbackError= */ null,
|
||||||
/* isLoading= */ false,
|
/* isLoading= */ false,
|
||||||
|
|
|
||||||
|
|
@ -662,6 +662,8 @@ public final class AnalyticsCollectorTest {
|
||||||
period0Seq0 /* SOURCE_UPDATE */,
|
period0Seq0 /* SOURCE_UPDATE */,
|
||||||
WINDOW_0 /* PLAYLIST_CHANGE */,
|
WINDOW_0 /* PLAYLIST_CHANGE */,
|
||||||
period0Seq1 /* SOURCE_UPDATE */);
|
period0Seq1 /* SOURCE_UPDATE */);
|
||||||
|
assertThat(listener.getEvents(EVENT_POSITION_DISCONTINUITY))
|
||||||
|
.containsExactly(WINDOW_0 /* REMOVE */);
|
||||||
assertThat(listener.getEvents(EVENT_IS_LOADING_CHANGED))
|
assertThat(listener.getEvents(EVENT_IS_LOADING_CHANGED))
|
||||||
.containsExactly(period0Seq0, period0Seq0, period0Seq1, period0Seq1)
|
.containsExactly(period0Seq0, period0Seq0, period0Seq1, period0Seq1)
|
||||||
.inOrder();
|
.inOrder();
|
||||||
|
|
@ -937,6 +939,9 @@ public final class AnalyticsCollectorTest {
|
||||||
period0Seq0 /* SOURCE_UPDATE (second item) */,
|
period0Seq0 /* SOURCE_UPDATE (second item) */,
|
||||||
period0Seq1 /* PLAYLIST_CHANGED (remove) */)
|
period0Seq1 /* PLAYLIST_CHANGED (remove) */)
|
||||||
.inOrder();
|
.inOrder();
|
||||||
|
assertThat(listener.getEvents(EVENT_POSITION_DISCONTINUITY))
|
||||||
|
.containsExactly(period0Seq1 /* REMOVE */)
|
||||||
|
.inOrder();
|
||||||
assertThat(listener.getEvents(EVENT_IS_LOADING_CHANGED))
|
assertThat(listener.getEvents(EVENT_IS_LOADING_CHANGED))
|
||||||
.containsExactly(period0Seq0, period0Seq0, period0Seq0, period0Seq0);
|
.containsExactly(period0Seq0, period0Seq0, period0Seq0, period0Seq0);
|
||||||
assertThat(listener.getEvents(EVENT_TRACKS_CHANGED))
|
assertThat(listener.getEvents(EVENT_TRACKS_CHANGED))
|
||||||
|
|
@ -1037,9 +1042,11 @@ public final class AnalyticsCollectorTest {
|
||||||
new Player.EventListener() {
|
new Player.EventListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onPositionDiscontinuity(
|
public void onPositionDiscontinuity(
|
||||||
|
Player.PositionInfo oldPosition,
|
||||||
|
Player.PositionInfo newPosition,
|
||||||
@Player.DiscontinuityReason int reason) {
|
@Player.DiscontinuityReason int reason) {
|
||||||
if (!player.isPlayingAd()
|
if (!player.isPlayingAd()
|
||||||
&& reason == Player.DISCONTINUITY_REASON_AD_INSERTION) {
|
&& reason == Player.DISCONTINUITY_REASON_AUTO_TRANSITION) {
|
||||||
// Finished playing ad. Marked as played.
|
// Finished playing ad. Marked as played.
|
||||||
adPlaybackState.set(
|
adPlaybackState.set(
|
||||||
adPlaybackState
|
adPlaybackState
|
||||||
|
|
@ -1651,7 +1658,7 @@ public final class AnalyticsCollectorTest {
|
||||||
player.addMediaSource(new FakeMediaSource(new FakeTimeline(), formats));
|
player.addMediaSource(new FakeMediaSource(new FakeTimeline(), formats));
|
||||||
player.play();
|
player.play();
|
||||||
TestPlayerRunHelper.runUntilPositionDiscontinuity(
|
TestPlayerRunHelper.runUntilPositionDiscontinuity(
|
||||||
player, Player.DISCONTINUITY_REASON_PERIOD_TRANSITION);
|
player, Player.DISCONTINUITY_REASON_AUTO_TRANSITION);
|
||||||
player.setMediaItem(MediaItem.fromUri("http://this-will-throw-an-exception.mp4"));
|
player.setMediaItem(MediaItem.fromUri("http://this-will-throw-an-exception.mp4"));
|
||||||
TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_IDLE);
|
TestPlayerRunHelper.runUntilPlaybackState(player, Player.STATE_IDLE);
|
||||||
ShadowLooper.runMainLooperToNextTask();
|
ShadowLooper.runMainLooperToNextTask();
|
||||||
|
|
@ -2085,7 +2092,11 @@ public final class AnalyticsCollectorTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPositionDiscontinuity(EventTime eventTime, int reason) {
|
public void onPositionDiscontinuity(
|
||||||
|
EventTime eventTime,
|
||||||
|
Player.PositionInfo oldPosition,
|
||||||
|
Player.PositionInfo newPosition,
|
||||||
|
int reason) {
|
||||||
reportedEvents.add(new ReportedEvent(EVENT_POSITION_DISCONTINUITY, eventTime));
|
reportedEvents.add(new ReportedEvent(EVENT_POSITION_DISCONTINUITY, eventTime));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -461,9 +461,9 @@ public final class DefaultPlaybackSessionManagerTest {
|
||||||
sessionManager.updateSessionsWithTimelineChange(contentEventTime1);
|
sessionManager.updateSessionsWithTimelineChange(contentEventTime1);
|
||||||
sessionManager.updateSessions(adEventTime1);
|
sessionManager.updateSessions(adEventTime1);
|
||||||
sessionManager.updateSessionsWithDiscontinuity(
|
sessionManager.updateSessionsWithDiscontinuity(
|
||||||
adEventTime1, Player.DISCONTINUITY_REASON_AD_INSERTION);
|
adEventTime1, Player.DISCONTINUITY_REASON_AUTO_TRANSITION);
|
||||||
sessionManager.updateSessionsWithDiscontinuity(
|
sessionManager.updateSessionsWithDiscontinuity(
|
||||||
contentEventTime2, Player.DISCONTINUITY_REASON_AD_INSERTION);
|
contentEventTime2, Player.DISCONTINUITY_REASON_AUTO_TRANSITION);
|
||||||
String adSessionId2 =
|
String adSessionId2 =
|
||||||
sessionManager.getSessionForMediaPeriodId(adTimeline, adEventTime2.mediaPeriodId);
|
sessionManager.getSessionForMediaPeriodId(adTimeline, adEventTime2.mediaPeriodId);
|
||||||
|
|
||||||
|
|
@ -751,7 +751,7 @@ public final class DefaultPlaybackSessionManagerTest {
|
||||||
sessionManager.updateSessions(eventTime2);
|
sessionManager.updateSessions(eventTime2);
|
||||||
|
|
||||||
sessionManager.updateSessionsWithDiscontinuity(
|
sessionManager.updateSessionsWithDiscontinuity(
|
||||||
eventTime2, Player.DISCONTINUITY_REASON_PERIOD_TRANSITION);
|
eventTime2, Player.DISCONTINUITY_REASON_AUTO_TRANSITION);
|
||||||
|
|
||||||
verify(mockListener).onSessionCreated(eq(eventTime1), anyString());
|
verify(mockListener).onSessionCreated(eq(eventTime1), anyString());
|
||||||
verify(mockListener).onSessionActive(eq(eventTime1), anyString());
|
verify(mockListener).onSessionActive(eq(eventTime1), anyString());
|
||||||
|
|
@ -781,7 +781,7 @@ public final class DefaultPlaybackSessionManagerTest {
|
||||||
sessionManager.getSessionForMediaPeriodId(timeline, eventTime2.mediaPeriodId);
|
sessionManager.getSessionForMediaPeriodId(timeline, eventTime2.mediaPeriodId);
|
||||||
|
|
||||||
sessionManager.updateSessionsWithDiscontinuity(
|
sessionManager.updateSessionsWithDiscontinuity(
|
||||||
eventTime2, Player.DISCONTINUITY_REASON_PERIOD_TRANSITION);
|
eventTime2, Player.DISCONTINUITY_REASON_AUTO_TRANSITION);
|
||||||
|
|
||||||
verify(mockListener).onSessionCreated(eventTime1, sessionId1);
|
verify(mockListener).onSessionCreated(eventTime1, sessionId1);
|
||||||
verify(mockListener).onSessionActive(eventTime1, sessionId1);
|
verify(mockListener).onSessionActive(eventTime1, sessionId1);
|
||||||
|
|
@ -960,7 +960,7 @@ public final class DefaultPlaybackSessionManagerTest {
|
||||||
adTimeline, contentEventTimeDuringPreroll.mediaPeriodId);
|
adTimeline, contentEventTimeDuringPreroll.mediaPeriodId);
|
||||||
|
|
||||||
sessionManager.updateSessionsWithDiscontinuity(
|
sessionManager.updateSessionsWithDiscontinuity(
|
||||||
contentEventTimeBetweenAds, Player.DISCONTINUITY_REASON_AD_INSERTION);
|
contentEventTimeBetweenAds, Player.DISCONTINUITY_REASON_AUTO_TRANSITION);
|
||||||
|
|
||||||
InOrder inOrder = inOrder(mockListener);
|
InOrder inOrder = inOrder(mockListener);
|
||||||
inOrder.verify(mockListener).onSessionCreated(contentEventTimeDuringPreroll, contentSessionId);
|
inOrder.verify(mockListener).onSessionCreated(contentEventTimeDuringPreroll, contentSessionId);
|
||||||
|
|
@ -1025,7 +1025,7 @@ public final class DefaultPlaybackSessionManagerTest {
|
||||||
sessionManager.updateSessions(adEventTime2);
|
sessionManager.updateSessions(adEventTime2);
|
||||||
|
|
||||||
sessionManager.updateSessionsWithDiscontinuity(
|
sessionManager.updateSessionsWithDiscontinuity(
|
||||||
adEventTime1, Player.DISCONTINUITY_REASON_AD_INSERTION);
|
adEventTime1, Player.DISCONTINUITY_REASON_AUTO_TRANSITION);
|
||||||
|
|
||||||
verify(mockListener, never()).onSessionFinished(any(), anyString(), anyBoolean());
|
verify(mockListener, never()).onSessionFinished(any(), anyString(), anyBoolean());
|
||||||
}
|
}
|
||||||
|
|
@ -1083,7 +1083,7 @@ public final class DefaultPlaybackSessionManagerTest {
|
||||||
sessionManager.getSessionForMediaPeriodId(adTimeline, adEventTime2.mediaPeriodId);
|
sessionManager.getSessionForMediaPeriodId(adTimeline, adEventTime2.mediaPeriodId);
|
||||||
|
|
||||||
sessionManager.updateSessionsWithDiscontinuity(
|
sessionManager.updateSessionsWithDiscontinuity(
|
||||||
adEventTime1, Player.DISCONTINUITY_REASON_AD_INSERTION);
|
adEventTime1, Player.DISCONTINUITY_REASON_AUTO_TRANSITION);
|
||||||
sessionManager.updateSessionsWithDiscontinuity(adEventTime2, Player.DISCONTINUITY_REASON_SEEK);
|
sessionManager.updateSessionsWithDiscontinuity(adEventTime2, Player.DISCONTINUITY_REASON_SEEK);
|
||||||
|
|
||||||
verify(mockListener).onSessionCreated(eq(contentEventTime), anyString());
|
verify(mockListener).onSessionCreated(eq(contentEventTime), anyString());
|
||||||
|
|
|
||||||
|
|
@ -1625,7 +1625,10 @@ public class PlayerView extends FrameLayout implements AdsLoader.AdViewProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPositionDiscontinuity(@DiscontinuityReason int reason) {
|
public void onPositionDiscontinuity(
|
||||||
|
Player.PositionInfo oldPosition,
|
||||||
|
Player.PositionInfo newPosition,
|
||||||
|
@DiscontinuityReason int reason) {
|
||||||
if (isPlayingAd() && controllerHideDuringAds) {
|
if (isPlayingAd() && controllerHideDuringAds) {
|
||||||
hideController();
|
hideController();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1647,7 +1647,10 @@ public class StyledPlayerView extends FrameLayout implements AdsLoader.AdViewPro
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPositionDiscontinuity(@DiscontinuityReason int reason) {
|
public void onPositionDiscontinuity(
|
||||||
|
Player.PositionInfo oldPosition,
|
||||||
|
Player.PositionInfo newPosition,
|
||||||
|
@DiscontinuityReason int reason) {
|
||||||
if (isPlayingAd() && controllerHideDuringAds) {
|
if (isPlayingAd() && controllerHideDuringAds) {
|
||||||
hideController();
|
hideController();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -158,8 +158,8 @@ public class TestPlayerRunHelper {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Runs tasks of the main {@link Looper} until a {@link
|
* Runs tasks of the main {@link Looper} until a {@link
|
||||||
* Player.EventListener#onPositionDiscontinuity} callback with the specified {@link
|
* Player.EventListener#onPositionDiscontinuity(Player.PositionInfo, Player.PositionInfo, int)}
|
||||||
* Player.DiscontinuityReason} occurred.
|
* callback with the specified {@link Player.DiscontinuityReason} occurred.
|
||||||
*
|
*
|
||||||
* @param player The {@link Player}.
|
* @param player The {@link Player}.
|
||||||
* @param expectedReason The expected {@link Player.DiscontinuityReason}.
|
* @param expectedReason The expected {@link Player.DiscontinuityReason}.
|
||||||
|
|
@ -173,7 +173,8 @@ public class TestPlayerRunHelper {
|
||||||
Player.EventListener listener =
|
Player.EventListener listener =
|
||||||
new Player.EventListener() {
|
new Player.EventListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onPositionDiscontinuity(int reason) {
|
public void onPositionDiscontinuity(
|
||||||
|
Player.PositionInfo oldPosition, Player.PositionInfo newPosition, int reason) {
|
||||||
if (reason == expectedReason) {
|
if (reason == expectedReason) {
|
||||||
receivedCallback.set(true);
|
receivedCallback.set(true);
|
||||||
player.removeListener(this);
|
player.removeListener(this);
|
||||||
|
|
|
||||||
|
|
@ -803,7 +803,10 @@ public abstract class Action {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Waits for {@link Player.EventListener#onPositionDiscontinuity(int)}. */
|
/**
|
||||||
|
* Waits for {@link Player.EventListener#onPositionDiscontinuity(Player.PositionInfo,
|
||||||
|
* Player.PositionInfo, int)}.
|
||||||
|
*/
|
||||||
public static final class WaitForPositionDiscontinuity extends Action {
|
public static final class WaitForPositionDiscontinuity extends Action {
|
||||||
|
|
||||||
/** @param tag A tag to use for logging. */
|
/** @param tag A tag to use for logging. */
|
||||||
|
|
@ -824,7 +827,10 @@ public abstract class Action {
|
||||||
player.addListener(
|
player.addListener(
|
||||||
new Player.EventListener() {
|
new Player.EventListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onPositionDiscontinuity(@Player.DiscontinuityReason int reason) {
|
public void onPositionDiscontinuity(
|
||||||
|
Player.PositionInfo oldPosition,
|
||||||
|
Player.PositionInfo newPosition,
|
||||||
|
@Player.DiscontinuityReason int reason) {
|
||||||
player.removeListener(this);
|
player.removeListener(this);
|
||||||
nextAction.schedule(player, trackSelector, surface, handler);
|
nextAction.schedule(player, trackSelector, surface, handler);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -575,7 +575,8 @@ public final class ExoPlayerTestRunner implements Player.EventListener, ActionSc
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asserts that {@link Player.EventListener#onPositionDiscontinuity(int)} was not called.
|
* Asserts that {@link Player.EventListener#onPositionDiscontinuity(Player.PositionInfo,
|
||||||
|
* Player.PositionInfo, int)} was not called.
|
||||||
*/
|
*/
|
||||||
public void assertNoPositionDiscontinuities() {
|
public void assertNoPositionDiscontinuities() {
|
||||||
assertThat(discontinuityReasons).isEmpty();
|
assertThat(discontinuityReasons).isEmpty();
|
||||||
|
|
@ -583,7 +584,8 @@ public final class ExoPlayerTestRunner implements Player.EventListener, ActionSc
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Asserts that the discontinuity reasons reported by {@link
|
* Asserts that the discontinuity reasons reported by {@link
|
||||||
* Player.EventListener#onPositionDiscontinuity(int)} are equal to the provided values.
|
* Player.EventListener#onPositionDiscontinuity(Player.PositionInfo, Player.PositionInfo, int)}
|
||||||
|
* are equal to the provided values.
|
||||||
*
|
*
|
||||||
* @param discontinuityReasons The expected discontinuity reasons.
|
* @param discontinuityReasons The expected discontinuity reasons.
|
||||||
*/
|
*/
|
||||||
|
|
@ -676,10 +678,15 @@ public final class ExoPlayerTestRunner implements Player.EventListener, ActionSc
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPositionDiscontinuity(@Player.DiscontinuityReason int reason) {
|
public void onPositionDiscontinuity(
|
||||||
|
Player.PositionInfo oldPosition,
|
||||||
|
Player.PositionInfo newPosition,
|
||||||
|
@Player.DiscontinuityReason int reason) {
|
||||||
discontinuityReasons.add(reason);
|
discontinuityReasons.add(reason);
|
||||||
int currentIndex = player.getCurrentPeriodIndex();
|
int currentIndex = player.getCurrentPeriodIndex();
|
||||||
if (reason == Player.DISCONTINUITY_REASON_PERIOD_TRANSITION
|
if ((reason == Player.DISCONTINUITY_REASON_AUTO_TRANSITION
|
||||||
|
&& oldPosition.adGroupIndex != C.INDEX_UNSET
|
||||||
|
&& newPosition.adGroupIndex != C.INDEX_UNSET)
|
||||||
|| periodIndices.isEmpty()
|
|| periodIndices.isEmpty()
|
||||||
|| periodIndices.get(periodIndices.size() - 1) != currentIndex) {
|
|| periodIndices.get(periodIndices.size() - 1) != currentIndex) {
|
||||||
// Ignore seek or internal discontinuities within a period.
|
// Ignore seek or internal discontinuities within a period.
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue