Search in sources :

Example 1 with ControllerInfo

use of androidx.media3.session.MediaSession.ControllerInfo 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);
}
Also used : DeviceInfo(androidx.media3.common.DeviceInfo)

Example 2 with ControllerInfo

use of androidx.media3.session.MediaSession.ControllerInfo in project media by androidx.

the class MediaControllerImplLegacy method buildNewControllerInfo.

private static ControllerInfo buildNewControllerInfo(boolean initialUpdate, LegacyPlayerInfo oldLegacyPlayerInfo, ControllerInfo oldControllerInfo, LegacyPlayerInfo newLegacyPlayerInfo, long sessionFlags, boolean isSessionReady, @RatingCompat.Style int ratingType, long timeDiffMs) {
    QueueTimeline currentTimeline;
    MediaMetadata mediaMetadata;
    int currentMediaItemIndex;
    MediaMetadata playlistMetadata;
    @RepeatMode int repeatMode;
    boolean shuffleModeEnabled;
    SessionCommands availableSessionCommands;
    Commands availablePlayerCommands;
    ImmutableList<CommandButton> customLayout;
    boolean isQueueChanged = oldLegacyPlayerInfo.queue != newLegacyPlayerInfo.queue;
    currentTimeline = isQueueChanged ? QueueTimeline.create(newLegacyPlayerInfo.queue) : new QueueTimeline((QueueTimeline) oldControllerInfo.playerInfo.timeline);
    boolean isMetadataCompatChanged = oldLegacyPlayerInfo.mediaMetadataCompat != newLegacyPlayerInfo.mediaMetadataCompat || initialUpdate;
    long oldActiveQueueId = getActiveQueueId(oldLegacyPlayerInfo.playbackStateCompat);
    long newActiveQueueId = getActiveQueueId(newLegacyPlayerInfo.playbackStateCompat);
    boolean isCurrentActiveQueueIdChanged = (oldActiveQueueId != newActiveQueueId) || initialUpdate;
    if (isMetadataCompatChanged || isCurrentActiveQueueIdChanged || isQueueChanged) {
        currentMediaItemIndex = findQueueItemIndex(newLegacyPlayerInfo.queue, newActiveQueueId);
        boolean hasMediaMetadataCompat = newLegacyPlayerInfo.mediaMetadataCompat != null;
        if (hasMediaMetadataCompat && isMetadataCompatChanged) {
            mediaMetadata = MediaUtils.convertToMediaMetadata(newLegacyPlayerInfo.mediaMetadataCompat, ratingType);
        } else if (!hasMediaMetadataCompat && isCurrentActiveQueueIdChanged) {
            mediaMetadata = (currentMediaItemIndex == C.INDEX_UNSET) ? MediaMetadata.EMPTY : MediaUtils.convertToMediaMetadata(newLegacyPlayerInfo.queue.get(currentMediaItemIndex).getDescription(), ratingType);
        } else {
            mediaMetadata = oldControllerInfo.playerInfo.mediaMetadata;
        }
        if (currentMediaItemIndex == C.INDEX_UNSET && isMetadataCompatChanged) {
            if (hasMediaMetadataCompat) {
                Log.w(TAG, "Adding a fake MediaItem at the end of the list because there's no QueueItem with" + " the active queue id and current Timeline should have currently playing" + " MediaItem.");
                MediaItem fakeMediaItem = MediaUtils.convertToMediaItem(newLegacyPlayerInfo.mediaMetadataCompat, ratingType);
                currentTimeline = currentTimeline.copyWithFakeMediaItem(fakeMediaItem);
                currentMediaItemIndex = currentTimeline.getWindowCount() - 1;
            } else {
                currentTimeline = currentTimeline.copyWithFakeMediaItem(/* fakeMediaItem= */
                null);
                // Shouldn't be C.INDEX_UNSET to make getCurrentMediaItemIndex() return masked index.
                // In other words, this index is either the currently playing media item index or the
                // would-be playing index when playing.
                currentMediaItemIndex = 0;
            }
        } else if (currentMediaItemIndex != C.INDEX_UNSET) {
            currentTimeline = currentTimeline.copyWithFakeMediaItem(/* fakeMediaItem= */
            null);
            if (hasMediaMetadataCompat) {
                MediaItem mediaItem = MediaUtils.convertToMediaItem(currentTimeline.getMediaItemAt(currentMediaItemIndex).mediaId, newLegacyPlayerInfo.mediaMetadataCompat, ratingType);
                currentTimeline = currentTimeline.copyWithNewMediaItem(/* replaceIndex= */
                currentMediaItemIndex, mediaItem);
            }
        } else {
            // There's queue, but no valid queue item ID nor current media item metadata.
            // Fallback to use 0 as current media item index to mask current item index.
            currentMediaItemIndex = 0;
        }
    } else {
        currentMediaItemIndex = oldControllerInfo.playerInfo.sessionPositionInfo.positionInfo.mediaItemIndex;
        mediaMetadata = oldControllerInfo.playerInfo.mediaMetadata;
    }
    playlistMetadata = oldLegacyPlayerInfo.queueTitle == newLegacyPlayerInfo.queueTitle ? oldControllerInfo.playerInfo.playlistMetadata : MediaUtils.convertToMediaMetadata(newLegacyPlayerInfo.queueTitle);
    repeatMode = MediaUtils.convertToRepeatMode(newLegacyPlayerInfo.repeatMode);
    shuffleModeEnabled = MediaUtils.convertToShuffleModeEnabled(newLegacyPlayerInfo.shuffleMode);
    if (oldLegacyPlayerInfo.playbackStateCompat != newLegacyPlayerInfo.playbackStateCompat) {
        availableSessionCommands = MediaUtils.convertToSessionCommands(newLegacyPlayerInfo.playbackStateCompat, isSessionReady);
        customLayout = MediaUtils.convertToCustomLayout(newLegacyPlayerInfo.playbackStateCompat);
    } else {
        availableSessionCommands = oldControllerInfo.availableSessionCommands;
        customLayout = oldControllerInfo.customLayout;
    }
    // Note: Sets the available player command here although it can be obtained before session is
    // ready. It's to follow the decision on MediaController to disallow any commands before
    // connection is made.
    availablePlayerCommands = (oldControllerInfo.availablePlayerCommands == Commands.EMPTY) ? MediaUtils.convertToPlayerCommands(sessionFlags, isSessionReady) : oldControllerInfo.availablePlayerCommands;
    PlaybackException playerError = MediaUtils.convertToPlaybackException(newLegacyPlayerInfo.playbackStateCompat);
    long durationMs = MediaUtils.convertToDurationMs(newLegacyPlayerInfo.mediaMetadataCompat);
    long currentPositionMs = MediaUtils.convertToCurrentPositionMs(newLegacyPlayerInfo.playbackStateCompat, newLegacyPlayerInfo.mediaMetadataCompat, timeDiffMs);
    long bufferedPositionMs = MediaUtils.convertToBufferedPositionMs(newLegacyPlayerInfo.playbackStateCompat, newLegacyPlayerInfo.mediaMetadataCompat, timeDiffMs);
    int bufferedPercentage = MediaUtils.convertToBufferedPercentage(newLegacyPlayerInfo.playbackStateCompat, newLegacyPlayerInfo.mediaMetadataCompat, timeDiffMs);
    long totalBufferedDurationMs = MediaUtils.convertToTotalBufferedDurationMs(newLegacyPlayerInfo.playbackStateCompat, newLegacyPlayerInfo.mediaMetadataCompat, timeDiffMs);
    boolean isPlayingAd = MediaUtils.convertToIsPlayingAd(newLegacyPlayerInfo.mediaMetadataCompat);
    PlaybackParameters playbackParameters = MediaUtils.convertToPlaybackParameters(newLegacyPlayerInfo.playbackStateCompat);
    AudioAttributes audioAttributes = MediaUtils.convertToAudioAttributes(newLegacyPlayerInfo.playbackInfoCompat);
    boolean playWhenReady = MediaUtils.convertToPlayWhenReady(newLegacyPlayerInfo.playbackStateCompat);
    @State int playbackState = MediaUtils.convertToPlaybackState(newLegacyPlayerInfo.playbackStateCompat, newLegacyPlayerInfo.mediaMetadataCompat, timeDiffMs);
    boolean isPlaying = MediaUtils.convertToIsPlaying(newLegacyPlayerInfo.playbackStateCompat);
    DeviceInfo deviceInfo = MediaUtils.convertToDeviceInfo(newLegacyPlayerInfo.playbackInfoCompat);
    int deviceVolume = MediaUtils.convertToDeviceVolume(newLegacyPlayerInfo.playbackInfoCompat);
    boolean deviceMuted = MediaUtils.convertToIsDeviceMuted(newLegacyPlayerInfo.playbackInfoCompat);
    long seekBackIncrementMs = oldControllerInfo.playerInfo.seekBackIncrementMs;
    long seekForwardIncrementMs = oldControllerInfo.playerInfo.seekForwardIncrementMs;
    return createControllerInfo(currentTimeline, mediaMetadata, currentMediaItemIndex, playlistMetadata, repeatMode, shuffleModeEnabled, availableSessionCommands, availablePlayerCommands, customLayout, playerError, durationMs, currentPositionMs, bufferedPositionMs, bufferedPercentage, totalBufferedDurationMs, isPlayingAd, playbackParameters, audioAttributes, playWhenReady, playbackState, isPlaying, deviceInfo, deviceVolume, deviceMuted, seekBackIncrementMs, seekForwardIncrementMs);
}
Also used : PlaybackException(androidx.media3.common.PlaybackException) AudioAttributes(androidx.media3.common.AudioAttributes) RepeatMode(androidx.media3.common.Player.RepeatMode) MediaItem(androidx.media3.common.MediaItem) State(androidx.media3.common.Player.State) Commands(androidx.media3.common.Player.Commands) DeviceInfo(androidx.media3.common.DeviceInfo) MediaMetadata(androidx.media3.common.MediaMetadata) PlaybackParameters(androidx.media3.common.PlaybackParameters)

Example 3 with ControllerInfo

use of androidx.media3.session.MediaSession.ControllerInfo 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);
}
Also used : MediaItem(androidx.media3.common.MediaItem) PositionInfo(androidx.media3.common.Player.PositionInfo) Nullable(androidx.annotation.Nullable)

Example 4 with ControllerInfo

use of androidx.media3.session.MediaSession.ControllerInfo 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);
}
Also used : Window(androidx.media3.common.Timeline.Window) DiscontinuityReason(androidx.media3.common.Player.DiscontinuityReason) IllegalSeekPositionException(androidx.media3.common.IllegalSeekPositionException) Timeline(androidx.media3.common.Timeline) MediaItemTransitionReason(androidx.media3.common.Player.MediaItemTransitionReason) PositionInfo(androidx.media3.common.Player.PositionInfo) Nullable(androidx.annotation.Nullable)

Example 5 with ControllerInfo

use of androidx.media3.session.MediaSession.ControllerInfo in project media by androidx.

the class MediaLibraryServiceLegacyStub method onSubscribe.

// TODO(b/192455639): Optimize potential multiple calls of
// MediaBrowserCompat.SubscriptionCallback#onChildrenLoaded() with the same
// content.
@Override
public void onSubscribe(String id, Bundle option) {
    @Nullable ControllerInfo controller = getCurrentController();
    if (controller == null) {
        return;
    }
    if (TextUtils.isEmpty(id)) {
        Log.w(TAG, "onSubscribe(): Ignoring empty id from " + controller);
        return;
    }
    postOrRun(librarySessionImpl.getApplicationHandler(), () -> {
        if (!getConnectedControllersManager().isSessionCommandAvailable(controller, SessionCommand.COMMAND_CODE_LIBRARY_SUBSCRIBE)) {
            return;
        }
        @Nullable LibraryParams params = MediaUtils.convertToLibraryParams(librarySessionImpl.getContext(), option);
        ignoreFuture(librarySessionImpl.onSubscribeOnHandler(controller, id, params));
    });
}
Also used : LibraryParams(androidx.media3.session.MediaLibraryService.LibraryParams) Nullable(androidx.annotation.Nullable) ControllerInfo(androidx.media3.session.MediaSession.ControllerInfo)

Aggregations

ControllerInfo (androidx.media3.session.MediaSession.ControllerInfo)44 Test (org.junit.Test)27 CountDownLatch (java.util.concurrent.CountDownLatch)26 Nullable (androidx.annotation.Nullable)22 LargeTest (androidx.test.filters.LargeTest)22 Bundle (android.os.Bundle)13 SessionCallback (androidx.media3.session.MediaSession.SessionCallback)12 Uri (android.net.Uri)8 RemoteException (android.os.RemoteException)7 LibraryParams (androidx.media3.session.MediaLibraryService.LibraryParams)7 AtomicReference (java.util.concurrent.atomic.AtomicReference)7 MediaItem (androidx.media3.common.MediaItem)6 ControllerCb (androidx.media3.session.MediaSession.ControllerCb)4 MediumTest (androidx.test.filters.MediumTest)4 DeadObjectException (android.os.DeadObjectException)3 PlaybackParameters (androidx.media3.common.PlaybackParameters)3 Rating (androidx.media3.common.Rating)3 DeviceInfo (androidx.media3.common.DeviceInfo)2 PlaybackException (androidx.media3.common.PlaybackException)2 COMMAND_SEEK_BACK (androidx.media3.common.Player.COMMAND_SEEK_BACK)2