use of androidx.media3.common.Player.MediaItemTransitionReason 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.MediaItemTransitionReason 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.MediaItemTransitionReason 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);
}
use of androidx.media3.common.Player.MediaItemTransitionReason in project media by androidx.
the class MediaControllerImplLegacy method createControllerInfo.
private static ControllerInfo createControllerInfo(QueueTimeline currentTimeline, MediaMetadata mediaMetadata, int currentMediaItemIndex, MediaMetadata playlistMetadata, @RepeatMode int repeatMode, boolean shuffleModeEnabled, SessionCommands availableSessionCommands, Commands availablePlayerCommands, ImmutableList<CommandButton> customLayout, @Nullable PlaybackException playerError, long durationMs, long currentPositionMs, long bufferedPositionMs, int bufferedPercentage, long totalBufferedDurationMs, boolean isPlayingAd, PlaybackParameters playbackParameters, AudioAttributes audioAttributes, boolean playWhenReady, int playbackState, boolean isPlaying, DeviceInfo deviceInfo, int deviceVolume, boolean deviceMuted, long seekBackIncrementMs, long seekForwardIncrementMs) {
@Nullable MediaItem currentMediaItem = currentTimeline.getMediaItemAt(currentMediaItemIndex);
PositionInfo positionInfo = createPositionInfo(currentMediaItemIndex, currentMediaItem, currentPositionMs);
SessionPositionInfo sessionPositionInfo = new SessionPositionInfo(/* positionInfo= */
positionInfo, /* isPlayingAd= */
isPlayingAd, /* eventTimeMs= */
C.TIME_UNSET, /* durationMs= */
durationMs, /* bufferedPositionMs= */
bufferedPositionMs, /* bufferedPercentage= */
bufferedPercentage, /* totalBufferedDurationMs= */
totalBufferedDurationMs, /* currentLiveOffsetMs= */
C.TIME_UNSET, /* contentDurationMs= */
durationMs, /* contentBufferedPositionMs= */
bufferedPositionMs);
PlayerInfo playerInfo = new PlayerInfo(/* playerError= */
playerError, /* mediaItemTransitionReason= */
PlayerInfo.MEDIA_ITEM_TRANSITION_REASON_DEFAULT, /* sessionPositionInfo= */
sessionPositionInfo, /* oldPositionInfo= */
SessionPositionInfo.DEFAULT_POSITION_INFO, /* newPositionInfo= */
SessionPositionInfo.DEFAULT_POSITION_INFO, /* discontinuityReason= */
PlayerInfo.DISCONTINUITY_REASON_DEFAULT, /* playbackParameters= */
playbackParameters, /* repeatMode= */
repeatMode, /* shuffleModeEnabled= */
shuffleModeEnabled, /* videoSize= */
VideoSize.UNKNOWN, /* timeline= */
currentTimeline, /* playlistMetadata= */
playlistMetadata, /* volume= */
1.0f, /* audioAttributes= */
audioAttributes, /* cues= */
Collections.emptyList(), /* deviceInfo= */
deviceInfo, /* deviceVolume= */
deviceVolume, /* deviceMuted= */
deviceMuted, /* playWhenReady= */
playWhenReady, /* playWhenReadyChangedReason= */
PlayerInfo.PLAY_WHEN_READY_CHANGE_REASON_DEFAULT, /* playbackSuppressionReason= */
Player.PLAYBACK_SUPPRESSION_REASON_NONE, /* playbackState= */
playbackState, /* isPlaying= */
isPlaying, /* isLoading= */
false, /* mediaMetadata= */
mediaMetadata, seekBackIncrementMs, seekForwardIncrementMs, /* maxSeekToPreviousPositionMs= */
0L, /* parameters= */
TrackSelectionParameters.DEFAULT_WITHOUT_CONTEXT);
return new ControllerInfo(playerInfo, availableSessionCommands, availablePlayerCommands, customLayout);
}
use of androidx.media3.common.Player.MediaItemTransitionReason in project media by androidx.
the class MediaControllerImplLegacy method seekToInternal.
private void seekToInternal(int mediaItemIndex, long positionMs) {
int currentMediaItemIndex = getCurrentMediaItemIndex();
Timeline currentTimeline = controllerInfo.playerInfo.timeline;
if (currentMediaItemIndex != mediaItemIndex && (mediaItemIndex < 0 || mediaItemIndex >= currentTimeline.getWindowCount())) {
throw new IllegalSeekPositionException(currentTimeline, mediaItemIndex, positionMs);
}
if (isPlayingAd()) {
return;
}
int newMediaItemIndex = currentMediaItemIndex;
@Nullable @MediaItemTransitionReason Integer mediaItemTransitionReason = null;
if (mediaItemIndex != currentMediaItemIndex) {
QueueTimeline queueTimeline = (QueueTimeline) controllerInfo.playerInfo.timeline;
long queueId = queueTimeline.getQueueId(mediaItemIndex);
if (queueId != QueueItem.UNKNOWN_ID) {
controllerCompat.getTransportControls().skipToQueueItem(queueId);
newMediaItemIndex = mediaItemIndex;
mediaItemTransitionReason = MEDIA_ITEM_TRANSITION_REASON_SEEK;
} else {
Log.w(TAG, "Cannot seek to new media item due to the missing queue Id at media item," + " mediaItemIndex=" + mediaItemIndex);
}
}
@Nullable @DiscontinuityReason Integer discontinuityReason;
long currentPositionMs = getCurrentPosition();
long newPositionMs;
if (positionMs == C.TIME_UNSET) {
newPositionMs = currentPositionMs;
discontinuityReason = null;
} else {
controllerCompat.getTransportControls().seekTo(positionMs);
newPositionMs = positionMs;
discontinuityReason = DISCONTINUITY_REASON_SEEK;
}
long newDurationMs;
long newBufferedPositionMs;
int newBufferedPercentage;
long newTotalBufferedDurationMs;
if (mediaItemTransitionReason == null) {
// Follows the ExoPlayerImpl's state masking for seek within the current item.
long oldBufferedPositionMs = getBufferedPosition();
newDurationMs = getDuration();
newBufferedPositionMs = (newPositionMs < currentPositionMs) ? newPositionMs : max(newPositionMs, oldBufferedPositionMs);
newBufferedPercentage = (newDurationMs == C.TIME_UNSET) ? 0 : (int) (newBufferedPositionMs * 100L / newDurationMs);
newTotalBufferedDurationMs = newBufferedPositionMs - newPositionMs;
} else {
newDurationMs = C.TIME_UNSET;
newBufferedPositionMs = 0L;
newBufferedPercentage = 0;
newTotalBufferedDurationMs = 0L;
}
PositionInfo positionInfo = createPositionInfo(newMediaItemIndex, !currentTimeline.isEmpty() ? currentTimeline.getWindow(newMediaItemIndex, new Window()).mediaItem : null, newPositionMs);
PlayerInfo maskedPlayerInfo = controllerInfo.playerInfo.copyWithSessionPositionInfo(createSessionPositionInfo(positionInfo, /* isPlayingAd= */
false, newDurationMs, newBufferedPositionMs, newBufferedPercentage, newTotalBufferedDurationMs));
if (maskedPlayerInfo.playbackState != Player.STATE_IDLE) {
maskedPlayerInfo = maskedPlayerInfo.copyWithPlaybackState(Player.STATE_BUFFERING, /* playerError= */
null);
}
ControllerInfo maskedControllerInfo = new ControllerInfo(maskedPlayerInfo, controllerInfo.availableSessionCommands, controllerInfo.availablePlayerCommands, controllerInfo.customLayout);
updateStateMaskedControllerInfo(maskedControllerInfo, discontinuityReason, mediaItemTransitionReason);
}
Aggregations