Move the ownership of MediaMetadata to ExoPlayerImpl.

Add the onMediaMetadataChanged event to onEvents.

PiperOrigin-RevId: 370738521
This commit is contained in:
samrobinson 2021-04-27 20:29:24 +01:00 committed by bachinger
parent 1d96d6b6b0
commit b336df3ed3
6 changed files with 99 additions and 41 deletions

View file

@ -23,6 +23,7 @@ import com.google.android.exoplayer2.util.Util;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.List;
/** Metadata of a {@link MediaItem} or a playlist. */
public final class MediaMetadata implements Bundleable {
@ -68,6 +69,27 @@ public final class MediaMetadata implements Bundleable {
return this;
}
/**
* Sets all fields supported by the {@link Metadata.Entry entries} within the list of {@link
* Metadata}.
*
* <p>Fields are only set if the {@link Metadata.Entry} has an implementation for {@link
* Metadata.Entry#populateMediaMetadata(Builder)}.
*
* <p>In the event that multiple {@link Metadata.Entry} objects within any of the {@link
* Metadata} relate to the same {@link MediaMetadata} field, then the last one will be used.
*/
public Builder populateFromMetadata(List<Metadata> metadataList) {
for (int i = 0; i < metadataList.size(); i++) {
Metadata metadata = metadataList.get(i);
for (int j = 0; j < metadata.length(); j++) {
Metadata.Entry entry = metadata.get(j);
entry.populateMediaMetadata(this);
}
}
return this;
}
/** Returns a new {@link MediaMetadata} instance with the current builder values. */
public MediaMetadata build() {
return new MediaMetadata(/* builder= */ this);

View file

@ -157,6 +157,9 @@ public interface Player {
* and the static and dynamic metadata sourced from {@link
* EventListener#onStaticMetadataChanged(List)} and {@link MetadataOutput#onMetadata(Metadata)}.
*
* <p>{@link #onEvents(Player, Events)} will also be called to report this event along with
* other events that happen in the same {@link Looper} message queue iteration.
*
* @param mediaMetadata The combined {@link MediaMetadata}.
*/
default void onMediaMetadataChanged(MediaMetadata mediaMetadata) {}
@ -899,7 +902,8 @@ public interface Player {
EVENT_PLAYER_ERROR,
EVENT_POSITION_DISCONTINUITY,
EVENT_PLAYBACK_PARAMETERS_CHANGED,
EVENT_AVAILABLE_COMMANDS_CHANGED
EVENT_AVAILABLE_COMMANDS_CHANGED,
EVENT_MEDIA_METADATA_CHANGED
})
@interface EventFlags {}
/** {@link #getCurrentTimeline()} changed. */
@ -935,6 +939,8 @@ public interface Player {
int EVENT_PLAYBACK_PARAMETERS_CHANGED = 13;
/** {@link #isCommandAvailable(int)} changed for at least one {@link Command}. */
int EVENT_AVAILABLE_COMMANDS_CHANGED = 14;
/** {@link #getMediaMetadata()} changed. */
int EVENT_MEDIA_METADATA_CHANGED = 15;
/**
* Commands that can be executed on a {@code Player}. One of {@link #COMMAND_PLAY_PAUSE}, {@link

View file

@ -102,6 +102,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
private ShuffleOrder shuffleOrder;
private boolean pauseAtEndOfMediaItems;
private Commands availableCommands;
private MediaMetadata mediaMetadata;
// Playback information when there is no pending seek/set source operation.
private PlaybackInfo playbackInfo;
@ -208,6 +209,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
.add(COMMAND_SEEK_TO_DEFAULT_POSITION)
.add(COMMAND_SEEK_TO_MEDIA_ITEM)
.build();
mediaMetadata = MediaMetadata.EMPTY;
maskingWindowIndex = C.INDEX_UNSET;
playbackInfoUpdateHandler = clock.createHandler(applicationLooper, /* callback= */ null);
playbackInfoUpdateListener =
@ -983,8 +985,18 @@ import java.util.concurrent.CopyOnWriteArraySet;
@Override
public MediaMetadata getMediaMetadata() {
// Unsupported operation.
return MediaMetadata.EMPTY;
return mediaMetadata;
}
public void onMetadata(Metadata metadata) {
MediaMetadata newMediaMetadata =
mediaMetadata.buildUpon().populateFromMetadata(metadata).build();
if (newMediaMetadata.equals(mediaMetadata)) {
return;
}
mediaMetadata = newMediaMetadata;
listeners.sendEvent(
EVENT_MEDIA_METADATA_CHANGED, listener -> listener.onMediaMetadataChanged(mediaMetadata));
}
@Override
@ -1194,6 +1206,24 @@ import java.util.concurrent.CopyOnWriteArraySet;
!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;
}
mediaMetadata = mediaItem != null ? mediaItem.mediaMetadata : MediaMetadata.EMPTY;
}
if (!previousPlaybackInfo.staticMetadata.equals(newPlaybackInfo.staticMetadata)) {
newMediaMetadata =
newMediaMetadata.buildUpon().populateFromMetadata(newPlaybackInfo.staticMetadata).build();
}
boolean metadataChanged = !newMediaMetadata.equals(mediaMetadata);
mediaMetadata = newMediaMetadata;
if (!previousPlaybackInfo.timeline.equals(newPlaybackInfo.timeline)) {
listeners.queueEvent(
Player.EVENT_TIMELINE_CHANGED,
@ -1222,18 +1252,10 @@ import java.util.concurrent.CopyOnWriteArraySet;
});
}
if (mediaItemTransitioned) {
@Nullable final MediaItem mediaItem;
if (!newPlaybackInfo.timeline.isEmpty()) {
int windowIndex =
newPlaybackInfo.timeline.getPeriodByUid(newPlaybackInfo.periodId.periodUid, period)
.windowIndex;
mediaItem = newPlaybackInfo.timeline.getWindow(windowIndex, window).mediaItem;
} else {
mediaItem = null;
}
@Nullable final MediaItem finalMediaItem = mediaItem;
listeners.queueEvent(
Player.EVENT_MEDIA_ITEM_TRANSITION,
listener -> listener.onMediaItemTransition(mediaItem, mediaItemTransitionReason));
listener -> listener.onMediaItemTransition(finalMediaItem, mediaItemTransitionReason));
}
if (previousPlaybackInfo.playbackError != newPlaybackInfo.playbackError
&& newPlaybackInfo.playbackError != null) {
@ -1254,6 +1276,12 @@ import java.util.concurrent.CopyOnWriteArraySet;
Player.EVENT_STATIC_METADATA_CHANGED,
listener -> listener.onStaticMetadataChanged(newPlaybackInfo.staticMetadata));
}
if (metadataChanged) {
final MediaMetadata finalMediaMetadata = mediaMetadata;
listeners.queueEvent(
Player.EVENT_MEDIA_METADATA_CHANGED,
listener -> listener.onMediaMetadataChanged(finalMediaMetadata));
}
if (previousPlaybackInfo.isLoading != newPlaybackInfo.isLoading) {
listeners.queueEvent(
Player.EVENT_IS_LOADING_CHANGED,

View file

@ -636,7 +636,6 @@ public class SimpleExoPlayer extends BasePlayer
private boolean isPriorityTaskManagerRegistered;
private boolean playerReleased;
private DeviceInfo deviceInfo;
private MediaMetadata currentMediaMetadata;
/** @deprecated Use the {@link Builder} and pass it to {@link #SimpleExoPlayer(Builder)}. */
@Deprecated
@ -749,7 +748,6 @@ public class SimpleExoPlayer extends BasePlayer
wifiLockManager = new WifiLockManager(builder.context);
wifiLockManager.setEnabled(builder.wakeMode == C.WAKE_MODE_NETWORK);
deviceInfo = createDeviceInfo(streamVolumeManager);
currentMediaMetadata = MediaMetadata.EMPTY;
sendRendererMessage(C.TRACK_TYPE_AUDIO, MSG_SET_AUDIO_SESSION_ID, audioSessionId);
sendRendererMessage(C.TRACK_TYPE_VIDEO, MSG_SET_AUDIO_SESSION_ID, audioSessionId);
@ -1656,7 +1654,7 @@ public class SimpleExoPlayer extends BasePlayer
@Override
public MediaMetadata getMediaMetadata() {
return currentMediaMetadata;
return player.getMediaMetadata();
}
@Override
@ -2069,14 +2067,6 @@ public class SimpleExoPlayer extends BasePlayer
return keepSessionIdAudioTrack.getAudioSessionId();
}
private void setMediaMetadata(MediaMetadata mediaMetadata) {
if (this.currentMediaMetadata.equals(mediaMetadata)) {
return;
}
this.currentMediaMetadata = mediaMetadata;
componentListener.onMediaMetadataChanged(this.currentMediaMetadata);
}
private static DeviceInfo createDeviceInfo(StreamVolumeManager streamVolumeManager) {
return new DeviceInfo(
DeviceInfo.PLAYBACK_TYPE_LOCAL,
@ -2252,7 +2242,7 @@ public class SimpleExoPlayer extends BasePlayer
@Override
public void onMetadata(Metadata metadata) {
analyticsCollector.onMetadata(metadata);
setMediaMetadata(getMediaMetadata().buildUpon().populateFromMetadata(metadata).build());
player.onMetadata(metadata);
for (MetadataOutput metadataOutput : metadataOutputs) {
metadataOutput.onMetadata(metadata);
}
@ -2376,22 +2366,6 @@ public class SimpleExoPlayer extends BasePlayer
}
}
@Override
public void onMediaItemTransition(
@Nullable MediaItem mediaItem, @MediaItemTransitionReason int reason) {
currentMediaMetadata = mediaItem == null ? MediaMetadata.EMPTY : mediaItem.mediaMetadata;
}
@Override
public void onStaticMetadataChanged(List<Metadata> metadataList) {
MediaMetadata.Builder metadataBuilder = getMediaMetadata().buildUpon();
for (int i = 0; i < metadataList.size(); i++) {
metadataBuilder.populateFromMetadata(metadataList.get(i));
}
setMediaMetadata(metadataBuilder.build());
}
@Override
public void onPlaybackStateChanged(@State int playbackState) {
updateWakeAndWifiLock();

View file

@ -25,6 +25,7 @@ import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.MediaMetadata;
import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Player.PlaybackSuppressionReason;
@ -732,6 +733,15 @@ public class AnalyticsCollector
listener -> listener.onPlaybackParametersChanged(eventTime, playbackParameters));
}
@Override
public void onMediaMetadataChanged(MediaMetadata mediaMetadata) {
EventTime eventTime = generateCurrentPlayerMediaPeriodEventTime();
sendEvent(
eventTime,
AnalyticsListener.EVENT_MEDIA_METADATA_CHANGED,
listener -> listener.onMediaMetadataChanged(eventTime, mediaMetadata));
}
@SuppressWarnings("deprecation") // Implementing and calling deprecated listener method.
@Override
public final void onSeekProcessed() {

View file

@ -29,6 +29,7 @@ import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.MediaMetadata;
import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.Player.DiscontinuityReason;
@ -42,6 +43,7 @@ import com.google.android.exoplayer2.decoder.DecoderException;
import com.google.android.exoplayer2.decoder.DecoderReuseEvaluation;
import com.google.android.exoplayer2.drm.DrmSession;
import com.google.android.exoplayer2.metadata.Metadata;
import com.google.android.exoplayer2.metadata.MetadataOutput;
import com.google.android.exoplayer2.source.LoadEventInfo;
import com.google.android.exoplayer2.source.MediaLoadData;
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
@ -166,6 +168,7 @@ public interface AnalyticsListener {
EVENT_PLAYER_ERROR,
EVENT_POSITION_DISCONTINUITY,
EVENT_PLAYBACK_PARAMETERS_CHANGED,
EVENT_MEDIA_METADATA_CHANGED,
EVENT_LOAD_STARTED,
EVENT_LOAD_COMPLETED,
EVENT_LOAD_CANCELED,
@ -242,6 +245,8 @@ public interface AnalyticsListener {
int EVENT_POSITION_DISCONTINUITY = Player.EVENT_POSITION_DISCONTINUITY;
/** {@link Player#getPlaybackParameters()} changed. */
int EVENT_PLAYBACK_PARAMETERS_CHANGED = Player.EVENT_PLAYBACK_PARAMETERS_CHANGED;
/** {@link Player#getMediaMetadata()} changed. */
int EVENT_MEDIA_METADATA_CHANGED = Player.EVENT_MEDIA_METADATA_CHANGED;
/** A source started loading data. */
int EVENT_LOAD_STARTED = 1000; // Intentional gap to leave space for new Player events
/** A source started completed loading data. */
@ -640,6 +645,19 @@ public interface AnalyticsListener {
*/
default void onStaticMetadataChanged(EventTime eventTime, List<Metadata> metadataList) {}
/**
* Called when the combined {@link MediaMetadata} changes.
*
* <p>The provided {@link MediaMetadata} is a combination of the {@link MediaItem#mediaMetadata}
* and the static and dynamic metadata sourced from {@link
* Player.EventListener#onStaticMetadataChanged(List)} and {@link
* MetadataOutput#onMetadata(Metadata)}.
*
* @param eventTime The event time.
* @param mediaMetadata The combined {@link MediaMetadata}.
*/
default void onMediaMetadataChanged(EventTime eventTime, MediaMetadata mediaMetadata) {}
/**
* Called when a media source started loading data.
*