From f80d1dc48dcc0539ac7faa20b085b0adc2c5fe64 Mon Sep 17 00:00:00 2001 From: Stypox Date: Fri, 22 Jul 2022 11:31:49 +0200 Subject: [PATCH] Let exoplayer decide when to update metadata Though still make sure metadata is updated after the thumbnail is loaded. This fixes the wrong seekbar properties (duration and current position) being shown in the notification sometimes. --- .../mediasession/MediaSessionManager.java | 87 ++++++++----------- .../mediasession/MediaSessionPlayerUi.java | 22 +---- 2 files changed, 40 insertions(+), 69 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/player/mediasession/MediaSessionManager.java b/app/src/main/java/org/schabi/newpipe/player/mediasession/MediaSessionManager.java index 98b6d1b32..c6766fbcb 100644 --- a/app/src/main/java/org/schabi/newpipe/player/mediasession/MediaSessionManager.java +++ b/app/src/main/java/org/schabi/newpipe/player/mediasession/MediaSessionManager.java @@ -2,10 +2,8 @@ package org.schabi.newpipe.player.mediasession; import android.content.Context; import android.content.Intent; -import android.graphics.Bitmap; import android.support.v4.media.MediaMetadataCompat; import android.support.v4.media.session.MediaSessionCompat; -import android.support.v4.media.session.PlaybackStateCompat; import android.util.Log; import android.view.KeyEvent; @@ -17,8 +15,12 @@ import com.google.android.exoplayer2.ForwardingPlayer; import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector; import org.schabi.newpipe.MainActivity; +import org.schabi.newpipe.R; import org.schabi.newpipe.player.Player; import org.schabi.newpipe.player.ui.VideoPlayerUi; +import org.schabi.newpipe.util.StreamTypeUtil; + +import java.util.Optional; public class MediaSessionManager { private static final String TAG = MediaSessionManager.class.getSimpleName(); @@ -34,17 +36,6 @@ public class MediaSessionManager { mediaSession = new MediaSessionCompat(context, TAG); mediaSession.setActive(true); - mediaSession.setPlaybackState(new PlaybackStateCompat.Builder() - .setState(PlaybackStateCompat.STATE_NONE, -1, 1) - .setActions(PlaybackStateCompat.ACTION_SEEK_TO - | PlaybackStateCompat.ACTION_PLAY - | PlaybackStateCompat.ACTION_PAUSE // was play and pause now play/pause - | PlaybackStateCompat.ACTION_SKIP_TO_NEXT - | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS - | PlaybackStateCompat.ACTION_SET_REPEAT_MODE - | PlaybackStateCompat.ACTION_STOP) - .build()); - sessionConnector = new MediaSessionConnector(mediaSession); sessionConnector.setQueueNavigator(new PlayQueueNavigator(mediaSession, player)); sessionConnector.setPlayer(new ForwardingPlayer(player.getExoPlayer()) { @@ -60,6 +51,37 @@ public class MediaSessionManager { player.pause(); } }); + + sessionConnector.setMetadataDeduplicationEnabled(true); + sessionConnector.setMediaMetadataProvider(exoPlayer -> { + if (DEBUG) { + Log.d(TAG, "MediaMetadataProvider#getMetadata called"); + } + + // set title and artist + final MediaMetadataCompat.Builder builder = new MediaMetadataCompat.Builder() + .putString(MediaMetadataCompat.METADATA_KEY_TITLE, player.getVideoTitle()) + .putString(MediaMetadataCompat.METADATA_KEY_ARTIST, player.getUploaderName()); + + // set duration (-1 for livestreams, since they don't have a duration) + final long duration = player.getCurrentStreamInfo() + .filter(info -> !StreamTypeUtil.isLiveStream(info.getStreamType())) + .map(info -> info.getDuration() * 1000L) + .orElse(-1L); + builder.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, duration); + + // set album art, unless the user asked not to, or there is no thumbnail available + final boolean showThumbnail = player.getPrefs().getBoolean( + context.getString(R.string.show_thumbnail_key), true); + Optional.ofNullable(player.getThumbnail()) + .filter(bitmap -> showThumbnail) + .ifPresent(bitmap -> { + builder.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, bitmap); + builder.putBitmap(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON, bitmap); + }); + + return builder.build(); + }); } @Nullable @@ -72,43 +94,8 @@ public class MediaSessionManager { return mediaSession.getSessionToken(); } - /** - * sets the Metadata - if required. - * - * @param title {@link MediaMetadataCompat#METADATA_KEY_TITLE} - * @param artist {@link MediaMetadataCompat#METADATA_KEY_ARTIST} - * @param albumArt {@link MediaMetadataCompat#METADATA_KEY_ALBUM_ART}, if not null - * @param duration {@link MediaMetadataCompat#METADATA_KEY_DURATION} - * - should be a negative value for unknown durations, e.g. for livestreams - */ - public void setMetadata(@NonNull final String title, - @NonNull final String artist, - @Nullable final Bitmap albumArt, - final long duration) { - if (DEBUG) { - Log.d(TAG, "setMetadata called with: title = [" + title + "], artist = [" + artist - + "], albumArt = [" + (albumArt == null ? "null" : albumArt.hashCode()) - + "], duration = [" + duration + "]"); - } - - if (!mediaSession.isActive()) { - if (DEBUG) { - Log.d(TAG, "setMetadata: media session not active, exiting"); - } - return; - } - - final MediaMetadataCompat.Builder builder = new MediaMetadataCompat.Builder() - .putString(MediaMetadataCompat.METADATA_KEY_TITLE, title) - .putString(MediaMetadataCompat.METADATA_KEY_ARTIST, artist) - .putLong(MediaMetadataCompat.METADATA_KEY_DURATION, duration); - - if (albumArt != null) { - builder.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, albumArt); - builder.putBitmap(MediaMetadataCompat.METADATA_KEY_DISPLAY_ICON, albumArt); - } - - mediaSession.setMetadata(builder.build()); + void triggerMetadataUpdate() { + sessionConnector.invalidateMediaSessionMetadata(); } /** diff --git a/app/src/main/java/org/schabi/newpipe/player/mediasession/MediaSessionPlayerUi.java b/app/src/main/java/org/schabi/newpipe/player/mediasession/MediaSessionPlayerUi.java index 2140be26d..c78a3a6b1 100644 --- a/app/src/main/java/org/schabi/newpipe/player/mediasession/MediaSessionPlayerUi.java +++ b/app/src/main/java/org/schabi/newpipe/player/mediasession/MediaSessionPlayerUi.java @@ -7,11 +7,8 @@ import android.support.v4.media.session.MediaSessionCompat; import androidx.annotation.NonNull; import androidx.annotation.Nullable; -import org.schabi.newpipe.R; -import org.schabi.newpipe.extractor.stream.StreamInfo; import org.schabi.newpipe.player.Player; import org.schabi.newpipe.player.ui.PlayerUi; -import org.schabi.newpipe.util.StreamTypeUtil; import java.util.Optional; @@ -47,25 +44,12 @@ public class MediaSessionPlayerUi extends PlayerUi { // TODO decide whether to handle ACTION_HEADSET_PLUG or not } - @Override - public void onMetadataChanged(@NonNull final StreamInfo info) { - super.onMetadataChanged(info); - - final boolean showThumbnail = player.getPrefs().getBoolean( - context.getString(R.string.show_thumbnail_key), true); - - mediaSessionManager.setMetadata( - player.getVideoTitle(), - player.getUploaderName(), - showThumbnail ? player.getThumbnail() : null, - StreamTypeUtil.isLiveStream(info.getStreamType()) ? -1 : info.getDuration() - ); - } - @Override public void onThumbnailLoaded(@Nullable final Bitmap bitmap) { super.onThumbnailLoaded(bitmap); - player.getCurrentStreamInfo().ifPresent(this::onMetadataChanged); + if (mediaSessionManager != null) { + mediaSessionManager.triggerMetadataUpdate(); + } } public void handleMediaButtonIntent(final Intent intent) {