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.
This commit is contained in:
Stypox 2022-07-22 11:31:49 +02:00 committed by litetex
parent 8bff445ec3
commit f80d1dc48d
2 changed files with 40 additions and 69 deletions

View file

@ -2,10 +2,8 @@ package org.schabi.newpipe.player.mediasession;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.graphics.Bitmap;
import android.support.v4.media.MediaMetadataCompat; import android.support.v4.media.MediaMetadataCompat;
import android.support.v4.media.session.MediaSessionCompat; import android.support.v4.media.session.MediaSessionCompat;
import android.support.v4.media.session.PlaybackStateCompat;
import android.util.Log; import android.util.Log;
import android.view.KeyEvent; import android.view.KeyEvent;
@ -17,8 +15,12 @@ import com.google.android.exoplayer2.ForwardingPlayer;
import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector; import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector;
import org.schabi.newpipe.MainActivity; import org.schabi.newpipe.MainActivity;
import org.schabi.newpipe.R;
import org.schabi.newpipe.player.Player; import org.schabi.newpipe.player.Player;
import org.schabi.newpipe.player.ui.VideoPlayerUi; import org.schabi.newpipe.player.ui.VideoPlayerUi;
import org.schabi.newpipe.util.StreamTypeUtil;
import java.util.Optional;
public class MediaSessionManager { public class MediaSessionManager {
private static final String TAG = MediaSessionManager.class.getSimpleName(); private static final String TAG = MediaSessionManager.class.getSimpleName();
@ -34,17 +36,6 @@ public class MediaSessionManager {
mediaSession = new MediaSessionCompat(context, TAG); mediaSession = new MediaSessionCompat(context, TAG);
mediaSession.setActive(true); 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 = new MediaSessionConnector(mediaSession);
sessionConnector.setQueueNavigator(new PlayQueueNavigator(mediaSession, player)); sessionConnector.setQueueNavigator(new PlayQueueNavigator(mediaSession, player));
sessionConnector.setPlayer(new ForwardingPlayer(player.getExoPlayer()) { sessionConnector.setPlayer(new ForwardingPlayer(player.getExoPlayer()) {
@ -60,6 +51,37 @@ public class MediaSessionManager {
player.pause(); 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 @Nullable
@ -72,43 +94,8 @@ public class MediaSessionManager {
return mediaSession.getSessionToken(); return mediaSession.getSessionToken();
} }
/** void triggerMetadataUpdate() {
* sets the Metadata - if required. sessionConnector.invalidateMediaSessionMetadata();
*
* @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());
} }
/** /**

View file

@ -7,11 +7,8 @@ import android.support.v4.media.session.MediaSessionCompat;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; 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.Player;
import org.schabi.newpipe.player.ui.PlayerUi; import org.schabi.newpipe.player.ui.PlayerUi;
import org.schabi.newpipe.util.StreamTypeUtil;
import java.util.Optional; import java.util.Optional;
@ -47,25 +44,12 @@ public class MediaSessionPlayerUi extends PlayerUi {
// TODO decide whether to handle ACTION_HEADSET_PLUG or not // 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 @Override
public void onThumbnailLoaded(@Nullable final Bitmap bitmap) { public void onThumbnailLoaded(@Nullable final Bitmap bitmap) {
super.onThumbnailLoaded(bitmap); super.onThumbnailLoaded(bitmap);
player.getCurrentStreamInfo().ifPresent(this::onMetadataChanged); if (mediaSessionManager != null) {
mediaSessionManager.triggerMetadataUpdate();
}
} }
public void handleMediaButtonIntent(final Intent intent) { public void handleMediaButtonIntent(final Intent intent) {