Search in sources :

Example 1 with State

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();
}
Also used : Timeline(androidx.media3.common.Timeline) Nullable(androidx.annotation.Nullable)

Example 2 with State

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;
}
Also used : TrackGroupArray(androidx.media3.common.TrackGroupArray) NullableType(org.checkerframework.checker.nullness.compatqual.NullableType) TracksInfo(androidx.media3.common.TracksInfo) TrackSelectionArray(androidx.media3.common.TrackSelectionArray) MediaTrack(com.google.android.gms.cast.MediaTrack) MediaInfo(com.google.android.gms.cast.MediaInfo) TrackGroup(androidx.media3.common.TrackGroup) TrackSelection(androidx.media3.common.TrackSelection) MediaStatus(com.google.android.gms.cast.MediaStatus)

Example 3 with State

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());
}
Also used : Player(androidx.media3.common.Player) InOrder(org.mockito.InOrder) MediaItem(androidx.media3.common.MediaItem) Test(org.junit.Test)

Example 4 with State

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();
}
Also used : Player(androidx.media3.common.Player) ExoPlayer(androidx.media3.exoplayer.ExoPlayer) CastPlayer(androidx.media3.cast.CastPlayer)

Example 5 with State

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);
        }
    }
}
Also used : AudioRendererEventListener(androidx.media3.exoplayer.audio.AudioRendererEventListener) VideoRendererEventListener(androidx.media3.exoplayer.video.VideoRendererEventListener) AnalyticsListener(androidx.media3.exoplayer.analytics.AnalyticsListener) VideoFrameMetadataListener(androidx.media3.exoplayer.video.VideoFrameMetadataListener) CameraMotionListener(androidx.media3.exoplayer.video.spherical.CameraMotionListener) SuppressLint(android.annotation.SuppressLint) TrackSelectionArray(androidx.media3.common.TrackSelectionArray) MediaItem(androidx.media3.common.MediaItem) MediaMetadata(androidx.media3.common.MediaMetadata) Nullable(androidx.annotation.Nullable)

Aggregations

Test (org.junit.Test)41 Timeline (androidx.media3.common.Timeline)17 Player (androidx.media3.common.Player)15 Nullable (androidx.annotation.Nullable)14 AdPlaybackState (androidx.media3.common.AdPlaybackState)14 CountDownLatch (java.util.concurrent.CountDownLatch)13 MediaItem (androidx.media3.common.MediaItem)12 LargeTest (androidx.test.filters.LargeTest)12 State (androidx.media3.common.Player.State)11 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)11 PositionInfo (androidx.media3.common.Player.PositionInfo)10 TestExoPlayerBuilder (androidx.media3.test.utils.TestExoPlayerBuilder)10 ServerSideAdInsertionUtil.addAdGroupToAdPlaybackState (androidx.media3.exoplayer.source.ads.ServerSideAdInsertionUtil.addAdGroupToAdPlaybackState)9 ActionSchedule (androidx.media3.test.utils.ActionSchedule)9 PlaybackStateCompat (android.support.v4.media.session.PlaybackStateCompat)8 SinglePeriodTimeline (androidx.media3.exoplayer.source.SinglePeriodTimeline)8 PlayerRunnable (androidx.media3.test.utils.ActionSchedule.PlayerRunnable)8 FakeTimeline (androidx.media3.test.utils.FakeTimeline)8 NoUidTimeline (androidx.media3.test.utils.NoUidTimeline)8 AtomicReference (java.util.concurrent.atomic.AtomicReference)8