use of androidx.media3.common.Player.State in project media by androidx.
the class CastPlayer method updateInternalStateAndNotifyIfChanged.
// Internal methods.
// Call deprecated callbacks.
@SuppressWarnings("deprecation")
private void updateInternalStateAndNotifyIfChanged() {
if (remoteMediaClient == null) {
// There is no session. We leave the state of the player as it is now.
return;
}
int oldWindowIndex = this.currentWindowIndex;
@Nullable Object oldPeriodUid = !getCurrentTimeline().isEmpty() ? getCurrentTimeline().getPeriod(oldWindowIndex, period, /* setIds= */
true).uid : null;
updatePlayerStateAndNotifyIfChanged(/* resultCallback= */
null);
updateRepeatModeAndNotifyIfChanged(/* resultCallback= */
null);
updatePlaybackRateAndNotifyIfChanged(/* resultCallback= */
null);
boolean playingPeriodChangedByTimelineChange = updateTimelineAndNotifyIfChanged();
Timeline currentTimeline = getCurrentTimeline();
currentWindowIndex = fetchCurrentWindowIndex(remoteMediaClient, currentTimeline);
@Nullable Object currentPeriodUid = !currentTimeline.isEmpty() ? currentTimeline.getPeriod(currentWindowIndex, period, /* setIds= */
true).uid : null;
if (!playingPeriodChangedByTimelineChange && !Util.areEqual(oldPeriodUid, currentPeriodUid) && pendingSeekCount == 0) {
// Report discontinuity and media item auto transition.
currentTimeline.getPeriod(oldWindowIndex, period, /* setIds= */
true);
currentTimeline.getWindow(oldWindowIndex, window);
long windowDurationMs = window.getDurationMs();
PositionInfo oldPosition = new PositionInfo(window.uid, period.windowIndex, window.mediaItem, period.uid, period.windowIndex, /* positionMs= */
windowDurationMs, /* contentPositionMs= */
windowDurationMs, /* adGroupIndex= */
C.INDEX_UNSET, /* adIndexInAdGroup= */
C.INDEX_UNSET);
currentTimeline.getPeriod(currentWindowIndex, period, /* setIds= */
true);
currentTimeline.getWindow(currentWindowIndex, window);
PositionInfo newPosition = new PositionInfo(window.uid, period.windowIndex, window.mediaItem, period.uid, period.windowIndex, /* positionMs= */
window.getDefaultPositionMs(), /* contentPositionMs= */
window.getDefaultPositionMs(), /* adGroupIndex= */
C.INDEX_UNSET, /* adIndexInAdGroup= */
C.INDEX_UNSET);
listeners.queueEvent(Player.EVENT_POSITION_DISCONTINUITY, listener -> {
listener.onPositionDiscontinuity(DISCONTINUITY_REASON_AUTO_TRANSITION);
listener.onPositionDiscontinuity(oldPosition, newPosition, DISCONTINUITY_REASON_AUTO_TRANSITION);
});
listeners.queueEvent(Player.EVENT_MEDIA_ITEM_TRANSITION, listener -> listener.onMediaItemTransition(getCurrentMediaItem(), MEDIA_ITEM_TRANSITION_REASON_AUTO));
}
if (updateTracksAndSelectionsAndNotifyIfChanged()) {
listeners.queueEvent(Player.EVENT_TRACKS_CHANGED, listener -> listener.onTracksChanged(currentTrackGroups, currentTrackSelection));
listeners.queueEvent(Player.EVENT_TRACKS_CHANGED, listener -> listener.onTracksInfoChanged(currentTracksInfo));
}
updateAvailableCommandsAndNotifyIfChanged();
listeners.flushEvents();
}
use of androidx.media3.common.Player.State in project media by androidx.
the class CastPlayer method updateTracksAndSelectionsAndNotifyIfChanged.
/**
* Updates the internal tracks and selection and returns whether they have changed.
*/
private boolean updateTracksAndSelectionsAndNotifyIfChanged() {
if (remoteMediaClient == null) {
// There is no session. We leave the state of the player as it is now.
return false;
}
MediaStatus mediaStatus = getMediaStatus();
MediaInfo mediaInfo = mediaStatus != null ? mediaStatus.getMediaInfo() : null;
List<MediaTrack> castMediaTracks = mediaInfo != null ? mediaInfo.getMediaTracks() : null;
if (castMediaTracks == null || castMediaTracks.isEmpty()) {
boolean hasChanged = !currentTrackGroups.isEmpty();
currentTrackGroups = TrackGroupArray.EMPTY;
currentTrackSelection = EMPTY_TRACK_SELECTION_ARRAY;
currentTracksInfo = TracksInfo.EMPTY;
return hasChanged;
}
long[] activeTrackIds = mediaStatus.getActiveTrackIds();
if (activeTrackIds == null) {
activeTrackIds = EMPTY_TRACK_ID_ARRAY;
}
TrackGroup[] trackGroups = new TrackGroup[castMediaTracks.size()];
@NullableType TrackSelection[] trackSelections = new TrackSelection[RENDERER_COUNT];
TracksInfo.TrackGroupInfo[] trackGroupInfos = new TracksInfo.TrackGroupInfo[castMediaTracks.size()];
for (int i = 0; i < castMediaTracks.size(); i++) {
MediaTrack mediaTrack = castMediaTracks.get(i);
trackGroups[i] = new TrackGroup(/* id= */
Integer.toString(i), CastUtils.mediaTrackToFormat(mediaTrack));
long id = mediaTrack.getId();
@C.TrackType int trackType = MimeTypes.getTrackType(mediaTrack.getContentType());
int rendererIndex = getRendererIndexForTrackType(trackType);
boolean supported = rendererIndex != C.INDEX_UNSET;
boolean selected = isTrackActive(id, activeTrackIds) && supported && trackSelections[rendererIndex] == null;
if (selected) {
trackSelections[rendererIndex] = new CastTrackSelection(trackGroups[i]);
}
@C.FormatSupport int[] trackSupport = new int[] { supported ? C.FORMAT_HANDLED : C.FORMAT_UNSUPPORTED_TYPE };
final boolean[] trackSelected = new boolean[] { selected };
trackGroupInfos[i] = new TracksInfo.TrackGroupInfo(trackGroups[i], trackSupport, trackType, trackSelected);
}
TrackGroupArray newTrackGroups = new TrackGroupArray(trackGroups);
TrackSelectionArray newTrackSelections = new TrackSelectionArray(trackSelections);
TracksInfo newTracksInfo = new TracksInfo(ImmutableList.copyOf(trackGroupInfos));
if (!newTrackGroups.equals(currentTrackGroups) || !newTrackSelections.equals(currentTrackSelection) || !newTracksInfo.equals(currentTracksInfo)) {
currentTrackSelection = newTrackSelections;
currentTrackGroups = newTrackGroups;
currentTracksInfo = newTracksInfo;
return true;
}
return false;
}
use of androidx.media3.common.Player.State in project media by androidx.
the class CastPlayerTest method autoTransition_notifiesPositionDiscontinuity.
@Test
// Mocks deprecated method used by the CastPlayer.
@SuppressWarnings("deprecation")
public void autoTransition_notifiesPositionDiscontinuity() {
int[] mediaQueueItemIds = new int[] { 1, 2 };
int[] streamTypes = { MediaInfo.STREAM_TYPE_BUFFERED, MediaInfo.STREAM_TYPE_BUFFERED };
long[] durationsFirstMs = { 12500, C.TIME_UNSET };
// When the remote Cast player transitions to an item that wasn't played before, the media state
// delivers the duration for that media item which updates the timeline accordingly.
long[] durationsSecondMs = { 12500, 22000 };
List<MediaItem> mediaItems = createMediaItems(mediaQueueItemIds);
castPlayer.addMediaItems(mediaItems);
updateTimeLine(mediaItems, mediaQueueItemIds, /* currentItemId= */
1, /* streamTypes= */
streamTypes, /* durationsMs= */
durationsFirstMs, /* positionMs= */
C.TIME_UNSET);
updateTimeLine(mediaItems, mediaQueueItemIds, /* currentItemId= */
2, /* streamTypes= */
streamTypes, /* durationsMs= */
durationsSecondMs, /* positionMs= */
C.TIME_UNSET);
Player.PositionInfo oldPosition = new Player.PositionInfo(/* windowUid= */
1, /* windowIndex= */
0, new MediaItem.Builder().setUri(Uri.EMPTY).setTag(1).build(), /* periodUid= */
1, /* periodIndex= */
0, /* positionMs= */
12500, /* contentPositionMs= */
12500, /* adGroupIndex= */
C.INDEX_UNSET, /* adIndexInAdGroup= */
C.INDEX_UNSET);
Player.PositionInfo newPosition = new Player.PositionInfo(/* windowUid= */
2, /* windowIndex= */
1, new MediaItem.Builder().setUri(Uri.EMPTY).setTag(2).build(), /* periodUid= */
2, /* periodIndex= */
1, /* positionMs= */
0, /* contentPositionMs= */
0, /* adGroupIndex= */
C.INDEX_UNSET, /* adIndexInAdGroup= */
C.INDEX_UNSET);
InOrder inOrder = Mockito.inOrder(mockListener);
inOrder.verify(mockListener).onPositionDiscontinuity(eq(Player.DISCONTINUITY_REASON_AUTO_TRANSITION));
inOrder.verify(mockListener).onPositionDiscontinuity(eq(oldPosition), eq(newPosition), eq(Player.DISCONTINUITY_REASON_AUTO_TRANSITION));
inOrder.verify(mockListener, never()).onPositionDiscontinuity(anyInt());
inOrder.verify(mockListener, never()).onPositionDiscontinuity(any(), any(), anyInt());
}
use of androidx.media3.common.Player.State in project media by androidx.
the class PlayerManager method setCurrentPlayer.
private void setCurrentPlayer(Player currentPlayer) {
if (this.currentPlayer == currentPlayer) {
return;
}
playerView.setPlayer(currentPlayer);
playerView.setControllerHideOnTouch(currentPlayer == localPlayer);
if (currentPlayer == castPlayer) {
playerView.setControllerShowTimeoutMs(0);
playerView.showController();
playerView.setDefaultArtwork(ResourcesCompat.getDrawable(context.getResources(), R.drawable.ic_baseline_cast_connected_400, /* theme= */
null));
} else {
// currentPlayer == localPlayer
playerView.setControllerShowTimeoutMs(PlayerControlView.DEFAULT_SHOW_TIMEOUT_MS);
playerView.setDefaultArtwork(null);
}
// Player state management.
long playbackPositionMs = C.TIME_UNSET;
int currentItemIndex = C.INDEX_UNSET;
boolean playWhenReady = false;
Player previousPlayer = this.currentPlayer;
if (previousPlayer != null) {
// Save state from the previous player.
int playbackState = previousPlayer.getPlaybackState();
if (playbackState != Player.STATE_ENDED) {
playbackPositionMs = previousPlayer.getCurrentPosition();
playWhenReady = previousPlayer.getPlayWhenReady();
currentItemIndex = previousPlayer.getCurrentMediaItemIndex();
if (currentItemIndex != this.currentItemIndex) {
playbackPositionMs = C.TIME_UNSET;
currentItemIndex = this.currentItemIndex;
}
}
previousPlayer.stop();
previousPlayer.clearMediaItems();
}
this.currentPlayer = currentPlayer;
// Media queue management.
currentPlayer.setMediaItems(mediaQueue, currentItemIndex, playbackPositionMs);
currentPlayer.setPlayWhenReady(playWhenReady);
currentPlayer.prepare();
}
use of androidx.media3.common.Player.State 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);
}
}
}
Aggregations