use of androidx.media3.common.Player.DiscontinuityReason in project media by androidx.
the class ExoPlayerImpl method updatePlaybackInfo.
// Calling deprecated listeners.
@SuppressWarnings("deprecation")
private void updatePlaybackInfo(PlaybackInfo playbackInfo, @TimelineChangeReason int timelineChangeReason, @PlayWhenReadyChangeReason int playWhenReadyChangeReason, boolean seekProcessed, boolean positionDiscontinuity, @DiscontinuityReason int positionDiscontinuityReason, long discontinuityWindowStartPositionUs, int oldMaskingMediaItemIndex) {
// 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.
PlaybackInfo previousPlaybackInfo = this.playbackInfo;
PlaybackInfo newPlaybackInfo = playbackInfo;
this.playbackInfo = playbackInfo;
Pair<Boolean, Integer> mediaItemTransitionInfo = evaluateMediaItemTransitionReason(newPlaybackInfo, previousPlaybackInfo, positionDiscontinuity, positionDiscontinuityReason, !previousPlaybackInfo.timeline.equals(newPlaybackInfo.timeline));
boolean mediaItemTransitioned = mediaItemTransitionInfo.first;
int mediaItemTransitionReason = mediaItemTransitionInfo.second;
MediaMetadata newMediaMetadata = mediaMetadata;
@Nullable MediaItem mediaItem = null;
if (mediaItemTransitioned) {
if (!newPlaybackInfo.timeline.isEmpty()) {
int windowIndex = newPlaybackInfo.timeline.getPeriodByUid(newPlaybackInfo.periodId.periodUid, period).windowIndex;
mediaItem = newPlaybackInfo.timeline.getWindow(windowIndex, window).mediaItem;
}
staticAndDynamicMediaMetadata = MediaMetadata.EMPTY;
}
if (mediaItemTransitioned || !previousPlaybackInfo.staticMetadata.equals(newPlaybackInfo.staticMetadata)) {
staticAndDynamicMediaMetadata = staticAndDynamicMediaMetadata.buildUpon().populateFromMetadata(newPlaybackInfo.staticMetadata).build();
newMediaMetadata = buildUpdatedMediaMetadata();
}
boolean metadataChanged = !newMediaMetadata.equals(mediaMetadata);
mediaMetadata = newMediaMetadata;
boolean playWhenReadyChanged = previousPlaybackInfo.playWhenReady != newPlaybackInfo.playWhenReady;
boolean playbackStateChanged = previousPlaybackInfo.playbackState != newPlaybackInfo.playbackState;
if (playbackStateChanged || playWhenReadyChanged) {
updateWakeAndWifiLock();
}
boolean isLoadingChanged = previousPlaybackInfo.isLoading != newPlaybackInfo.isLoading;
if (isLoadingChanged) {
updatePriorityTaskManagerForIsLoadingChange(newPlaybackInfo.isLoading);
}
if (!previousPlaybackInfo.timeline.equals(newPlaybackInfo.timeline)) {
listeners.queueEvent(Player.EVENT_TIMELINE_CHANGED, listener -> listener.onTimelineChanged(newPlaybackInfo.timeline, timelineChangeReason));
}
if (positionDiscontinuity) {
PositionInfo previousPositionInfo = getPreviousPositionInfo(positionDiscontinuityReason, previousPlaybackInfo, oldMaskingMediaItemIndex);
PositionInfo positionInfo = getPositionInfo(discontinuityWindowStartPositionUs);
listeners.queueEvent(Player.EVENT_POSITION_DISCONTINUITY, listener -> {
listener.onPositionDiscontinuity(positionDiscontinuityReason);
listener.onPositionDiscontinuity(previousPositionInfo, positionInfo, positionDiscontinuityReason);
});
}
if (mediaItemTransitioned) {
@Nullable final MediaItem finalMediaItem = mediaItem;
listeners.queueEvent(Player.EVENT_MEDIA_ITEM_TRANSITION, listener -> listener.onMediaItemTransition(finalMediaItem, mediaItemTransitionReason));
}
if (previousPlaybackInfo.playbackError != newPlaybackInfo.playbackError) {
listeners.queueEvent(Player.EVENT_PLAYER_ERROR, listener -> listener.onPlayerErrorChanged(newPlaybackInfo.playbackError));
if (newPlaybackInfo.playbackError != null) {
listeners.queueEvent(Player.EVENT_PLAYER_ERROR, listener -> listener.onPlayerError(newPlaybackInfo.playbackError));
}
}
if (previousPlaybackInfo.trackSelectorResult != newPlaybackInfo.trackSelectorResult) {
trackSelector.onSelectionActivated(newPlaybackInfo.trackSelectorResult.info);
TrackSelectionArray newSelection = new TrackSelectionArray(newPlaybackInfo.trackSelectorResult.selections);
listeners.queueEvent(Player.EVENT_TRACKS_CHANGED, listener -> listener.onTracksChanged(newPlaybackInfo.trackGroups, newSelection));
listeners.queueEvent(Player.EVENT_TRACKS_CHANGED, listener -> listener.onTracksInfoChanged(newPlaybackInfo.trackSelectorResult.tracksInfo));
}
if (metadataChanged) {
final MediaMetadata finalMediaMetadata = mediaMetadata;
listeners.queueEvent(EVENT_MEDIA_METADATA_CHANGED, listener -> listener.onMediaMetadataChanged(finalMediaMetadata));
}
if (isLoadingChanged) {
listeners.queueEvent(Player.EVENT_IS_LOADING_CHANGED, listener -> {
listener.onLoadingChanged(newPlaybackInfo.isLoading);
listener.onIsLoadingChanged(newPlaybackInfo.isLoading);
});
}
if (playbackStateChanged || playWhenReadyChanged) {
listeners.queueEvent(/* eventFlag= */
C.INDEX_UNSET, listener -> listener.onPlayerStateChanged(newPlaybackInfo.playWhenReady, newPlaybackInfo.playbackState));
}
if (playbackStateChanged) {
listeners.queueEvent(Player.EVENT_PLAYBACK_STATE_CHANGED, listener -> listener.onPlaybackStateChanged(newPlaybackInfo.playbackState));
}
if (playWhenReadyChanged) {
listeners.queueEvent(Player.EVENT_PLAY_WHEN_READY_CHANGED, listener -> listener.onPlayWhenReadyChanged(newPlaybackInfo.playWhenReady, playWhenReadyChangeReason));
}
if (previousPlaybackInfo.playbackSuppressionReason != newPlaybackInfo.playbackSuppressionReason) {
listeners.queueEvent(Player.EVENT_PLAYBACK_SUPPRESSION_REASON_CHANGED, listener -> listener.onPlaybackSuppressionReasonChanged(newPlaybackInfo.playbackSuppressionReason));
}
if (isPlaying(previousPlaybackInfo) != isPlaying(newPlaybackInfo)) {
listeners.queueEvent(Player.EVENT_IS_PLAYING_CHANGED, listener -> listener.onIsPlayingChanged(isPlaying(newPlaybackInfo)));
}
if (!previousPlaybackInfo.playbackParameters.equals(newPlaybackInfo.playbackParameters)) {
listeners.queueEvent(Player.EVENT_PLAYBACK_PARAMETERS_CHANGED, listener -> listener.onPlaybackParametersChanged(newPlaybackInfo.playbackParameters));
}
if (seekProcessed) {
listeners.queueEvent(/* eventFlag= */
C.INDEX_UNSET, Listener::onSeekProcessed);
}
updateAvailableCommands();
listeners.flushEvents();
if (previousPlaybackInfo.offloadSchedulingEnabled != newPlaybackInfo.offloadSchedulingEnabled) {
for (AudioOffloadListener listener : audioOffloadListeners) {
listener.onExperimentalOffloadSchedulingEnabledChanged(newPlaybackInfo.offloadSchedulingEnabled);
}
}
if (previousPlaybackInfo.sleepingForOffload != newPlaybackInfo.sleepingForOffload) {
for (AudioOffloadListener listener : audioOffloadListeners) {
listener.onExperimentalSleepingForOffloadChanged(newPlaybackInfo.sleepingForOffload);
}
}
}
use of androidx.media3.common.Player.DiscontinuityReason in project media by androidx.
the class ExoPlayerTest method clippedLoopedPeriodsArePlayedFully.
@Test
public void clippedLoopedPeriodsArePlayedFully() throws Exception {
long startPositionUs = 300_000;
long expectedDurationUs = 700_000;
MediaSource mediaSource = new ClippingMediaSource(new FakeMediaSource(), startPositionUs, startPositionUs + expectedDurationUs);
Clock clock = new FakeClock(/* isAutoAdvancing= */
true);
AtomicReference<Player> playerReference = new AtomicReference<>();
AtomicLong positionAtDiscontinuityMs = new AtomicLong(C.TIME_UNSET);
AtomicLong clockAtStartMs = new AtomicLong(C.TIME_UNSET);
AtomicLong clockAtDiscontinuityMs = new AtomicLong(C.TIME_UNSET);
Player.Listener playerListener = new Player.Listener() {
@Override
public void onPlaybackStateChanged(@Player.State int playbackState) {
if (playbackState == Player.STATE_READY && clockAtStartMs.get() == C.TIME_UNSET) {
clockAtStartMs.set(clock.elapsedRealtime());
}
}
@Override
public void onPositionDiscontinuity(@DiscontinuityReason int reason) {
if (reason == Player.DISCONTINUITY_REASON_AUTO_TRANSITION) {
positionAtDiscontinuityMs.set(playerReference.get().getCurrentPosition());
clockAtDiscontinuityMs.set(clock.elapsedRealtime());
}
}
};
ActionSchedule actionSchedule = new ActionSchedule.Builder(TAG).executeRunnable(new PlayerRunnable() {
@Override
public void run(ExoPlayer player) {
playerReference.set(player);
player.addListener(playerListener);
}
}).pause().setRepeatMode(Player.REPEAT_MODE_ALL).waitForPlaybackState(Player.STATE_READY).playUntilPosition(/* mediaItemIndex= */
0, /* positionMs= */
1).playUntilStartOfMediaItem(/* mediaItemIndex= */
0).setRepeatMode(Player.REPEAT_MODE_OFF).play().build();
new ExoPlayerTestRunner.Builder(context).setClock(clock).setMediaSources(mediaSource).setActionSchedule(actionSchedule).build().start().blockUntilEnded(TIMEOUT_MS);
assertThat(positionAtDiscontinuityMs.get()).isAtLeast(0L);
assertThat(clockAtDiscontinuityMs.get() - clockAtStartMs.get()).isAtLeast(Util.usToMs(expectedDurationUs));
}
use of androidx.media3.common.Player.DiscontinuityReason in project media by androidx.
the class ExoPlayerTest method contentWithInitialSeekPositionAfterPrerollAdStartsAtSeekPosition.
@Test
public void contentWithInitialSeekPositionAfterPrerollAdStartsAtSeekPosition() throws Exception {
AdPlaybackState adPlaybackState = FakeTimeline.createAdPlaybackState(/* adsPerAdGroup= */
3, /* adGroupTimesUs...= */
0);
Timeline fakeTimeline = new FakeTimeline(new TimelineWindowDefinition(/* periodCount= */
1, /* id= */
0, /* isSeekable= */
true, /* isDynamic= */
false, /* durationUs= */
10_000_000, adPlaybackState));
FakeMediaSource fakeMediaSource = new FakeMediaSource(/* timeline= */
null);
AtomicReference<Player> playerReference = new AtomicReference<>();
AtomicLong contentStartPositionMs = new AtomicLong(C.TIME_UNSET);
Player.Listener playerListener = new Player.Listener() {
@Override
public void onPositionDiscontinuity(@DiscontinuityReason int reason) {
if (reason == Player.DISCONTINUITY_REASON_AUTO_TRANSITION) {
contentStartPositionMs.set(playerReference.get().getContentPosition());
}
}
};
ActionSchedule actionSchedule = new ActionSchedule.Builder(TAG).executeRunnable(new PlayerRunnable() {
@Override
public void run(ExoPlayer player) {
playerReference.set(player);
player.addListener(playerListener);
}
}).seek(/* positionMs= */
5_000).waitForPlaybackState(Player.STATE_BUFFERING).executeRunnable(() -> fakeMediaSource.setNewSourceInfo(fakeTimeline)).build();
new ExoPlayerTestRunner.Builder(context).setMediaSources(fakeMediaSource).setActionSchedule(actionSchedule).build().start().blockUntilEnded(TIMEOUT_MS);
assertThat(contentStartPositionMs.get()).isAtLeast(5_000L);
}
use of androidx.media3.common.Player.DiscontinuityReason in project media by androidx.
the class PlayerInfo method fromBundle.
private static PlayerInfo fromBundle(Bundle bundle) {
@Nullable PlaybackException playerError = BundleableUtil.fromNullableBundle(PlaybackException.CREATOR, bundle.getBundle(keyForField(FIELD_PLAYBACK_ERROR)));
int mediaItemTransitionReason = bundle.getInt(keyForField(FIELD_MEDIA_ITEM_TRANSITION_REASON), MEDIA_ITEM_TRANSITION_REASON_REPEAT);
SessionPositionInfo sessionPositionInfo = BundleableUtil.fromNullableBundle(SessionPositionInfo.CREATOR, bundle.getBundle(keyForField(FIELD_SESSION_POSITION_INFO)), SessionPositionInfo.DEFAULT);
PositionInfo oldPositionInfo = BundleableUtil.fromNullableBundle(PositionInfo.CREATOR, bundle.getBundle(keyForField(FIELD_OLD_POSITION_INFO)), SessionPositionInfo.DEFAULT_POSITION_INFO);
PositionInfo newPositionInfo = BundleableUtil.fromNullableBundle(PositionInfo.CREATOR, bundle.getBundle(keyForField(FIELD_NEW_POSITION_INFO)), SessionPositionInfo.DEFAULT_POSITION_INFO);
int discontinuityReason = bundle.getInt(keyForField(FIELD_DISCONTINUITY_REASON), DISCONTINUITY_REASON_AUTO_TRANSITION);
@Nullable Bundle playbackParametersBundle = bundle.getBundle(keyForField(FIELD_PLAYBACK_PARAMETERS));
PlaybackParameters playbackParameters = BundleableUtil.fromNullableBundle(PlaybackParameters.CREATOR, playbackParametersBundle, /* defaultValue= */
PlaybackParameters.DEFAULT);
@Player.RepeatMode int repeatMode = bundle.getInt(keyForField(FIELD_REPEAT_MODE), /* defaultValue= */
Player.REPEAT_MODE_OFF);
boolean shuffleModeEnabled = bundle.getBoolean(keyForField(FIELD_SHUFFLE_MODE_ENABLED), /* defaultValue= */
false);
Timeline timeline = BundleableUtil.fromNullableBundle(Timeline.CREATOR, bundle.getBundle(keyForField(FIELD_TIMELINE)), Timeline.EMPTY);
VideoSize videoSize = BundleableUtil.fromNullableBundle(VideoSize.CREATOR, bundle.getBundle(keyForField(FIELD_VIDEO_SIZE)), VideoSize.UNKNOWN);
MediaMetadata playlistMetadata = BundleableUtil.fromNullableBundle(MediaMetadata.CREATOR, bundle.getBundle(keyForField(FIELD_PLAYLIST_METADATA)), MediaMetadata.EMPTY);
float volume = bundle.getFloat(keyForField(FIELD_VOLUME), /* defaultValue= */
1);
AudioAttributes audioAttributes = BundleableUtil.fromNullableBundle(AudioAttributes.CREATOR, bundle.getBundle(keyForField(FIELD_AUDIO_ATTRIBUTES)), /* defaultValue= */
AudioAttributes.DEFAULT);
List<Cue> cues = BundleableUtil.fromBundleNullableList(Cue.CREATOR, bundle.getParcelableArrayList(keyForField(FIELD_CUES)), /* defaultValue= */
ImmutableList.of());
@Nullable Bundle deviceInfoBundle = bundle.getBundle(keyForField(FIELD_DEVICE_INFO));
DeviceInfo deviceInfo = BundleableUtil.fromNullableBundle(DeviceInfo.CREATOR, deviceInfoBundle, /* defaultValue= */
DeviceInfo.UNKNOWN);
int deviceVolume = bundle.getInt(keyForField(FIELD_DEVICE_VOLUME), /* defaultValue= */
0);
boolean deviceMuted = bundle.getBoolean(keyForField(FIELD_DEVICE_MUTED), /* defaultValue= */
false);
boolean playWhenReady = bundle.getBoolean(keyForField(FIELD_PLAY_WHEN_READY), /* defaultValue= */
false);
int playWhenReadyChangedReason = bundle.getInt(keyForField(FIELD_PLAY_WHEN_READY_CHANGED_REASON), /* defaultValue= */
PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST);
@Player.PlaybackSuppressionReason int playbackSuppressionReason = bundle.getInt(keyForField(FIELD_PLAYBACK_SUPPRESSION_REASON), /* defaultValue= */
PLAYBACK_SUPPRESSION_REASON_NONE);
@Player.State int playbackState = bundle.getInt(keyForField(FIELD_PLAYBACK_STATE), /* defaultValue= */
STATE_IDLE);
boolean isPlaying = bundle.getBoolean(keyForField(FIELD_IS_PLAYING), /* defaultValue= */
false);
boolean isLoading = bundle.getBoolean(keyForField(FIELD_IS_LOADING), /* defaultValue= */
false);
MediaMetadata mediaMetadata = BundleableUtil.fromNullableBundle(MediaMetadata.CREATOR, bundle.getBundle(keyForField(FIELD_MEDIA_METADATA)), MediaMetadata.EMPTY);
long seekBackIncrementMs = bundle.getLong(keyForField(FIELD_SEEK_BACK_INCREMENT_MS), /* defaultValue= */
0);
long seekForwardIncrementMs = bundle.getLong(keyForField(FIELD_SEEK_FORWARD_INCREMENT_MS), /* defaultValue= */
0);
long maxSeekToPreviousPosition = bundle.getLong(keyForField(FIELD_MAX_SEEK_TO_PREVIOUS_POSITION_MS), /* defaultValue= */
0);
TrackSelectionParameters trackSelectionParameters = BundleableUtil.fromNullableBundle(TrackSelectionParameters.CREATOR, bundle.getBundle(keyForField(FIELD_TRACK_SELECTION_PARAMETERS)), TrackSelectionParameters.DEFAULT_WITHOUT_CONTEXT);
return new PlayerInfo(playerError, mediaItemTransitionReason, sessionPositionInfo, oldPositionInfo, newPositionInfo, discontinuityReason, playbackParameters, repeatMode, shuffleModeEnabled, videoSize, timeline, playlistMetadata, volume, audioAttributes, cues, deviceInfo, deviceVolume, deviceMuted, playWhenReady, playWhenReadyChangedReason, playbackSuppressionReason, playbackState, isPlaying, isLoading, mediaMetadata, seekBackIncrementMs, seekForwardIncrementMs, maxSeekToPreviousPosition, trackSelectionParameters);
}
use of androidx.media3.common.Player.DiscontinuityReason in project media by androidx.
the class MediaControllerImplLegacy method setDeviceVolume.
@Override
public void setDeviceVolume(int volume) {
DeviceInfo deviceInfo = getDeviceInfo();
int minVolume = deviceInfo.minVolume;
int maxVolume = deviceInfo.maxVolume;
if (minVolume <= volume && volume <= maxVolume) {
boolean isDeviceMuted = isDeviceMuted();
ControllerInfo maskedControllerInfo = new ControllerInfo(controllerInfo.playerInfo.copyWithDeviceVolume(volume, isDeviceMuted), controllerInfo.availableSessionCommands, controllerInfo.availablePlayerCommands, controllerInfo.customLayout);
updateStateMaskedControllerInfo(maskedControllerInfo, /* discontinuityReason= */
null, /* mediaItemTransitionReason= */
null);
}
controllerCompat.setVolumeTo(volume, VOLUME_FLAGS);
}
Aggregations