diff --git a/library/common/src/main/java/com/google/android/exoplayer2/MediaMetadata.java b/library/common/src/main/java/com/google/android/exoplayer2/MediaMetadata.java index 0da1c8271c..baf916c3c9 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/MediaMetadata.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/MediaMetadata.java @@ -18,6 +18,7 @@ package com.google.android.exoplayer2; import android.os.Bundle; import androidx.annotation.IntDef; import androidx.annotation.Nullable; +import com.google.android.exoplayer2.metadata.Metadata; import com.google.android.exoplayer2.util.Util; import java.lang.annotation.Documented; import java.lang.annotation.Retention; @@ -29,20 +30,37 @@ public final class MediaMetadata implements Bundleable { /** A builder for {@link MediaMetadata} instances. */ public static final class Builder { + @Nullable private String title; + public Builder() {} private Builder(MediaMetadata mediaMetadata) { this.title = mediaMetadata.title; } - @Nullable private String title; - /** Sets the optional title. */ public Builder setTitle(@Nullable String title) { this.title = title; return this; } + /** + * Sets all fields supported by the {@link Metadata.Entry entries} within the {@link Metadata}. + * + *

Fields are only set if the {@link Metadata.Entry} has an implementation for {@link + * Metadata.Entry#populateMediaMetadata(Builder)}. + * + *

In the event that multiple {@link Metadata.Entry} objects within the {@link Metadata} + * relate to the same {@link MediaMetadata} field, then the last one will be used. + */ + public Builder populateFromMetadata(Metadata metadata) { + for (int i = 0; i < metadata.length(); i++) { + Metadata.Entry entry = metadata.get(i); + entry.populateMediaMetadata(this); + } + return this; + } + /** Returns a new {@link MediaMetadata} instance with the current builder values. */ public MediaMetadata build() { return new MediaMetadata(/* builder= */ this); diff --git a/library/common/src/main/java/com/google/android/exoplayer2/Player.java b/library/common/src/main/java/com/google/android/exoplayer2/Player.java index 66121aa6ee..1813963453 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/Player.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/Player.java @@ -150,6 +150,17 @@ public interface Player { */ default void onStaticMetadataChanged(List metadataList) {} + /** + * Called when the combined {@link MediaMetadata} changes. + * + *

The provided {@link MediaMetadata} is a combination of the {@link MediaItem#mediaMetadata} + * and the static and dynamic metadata sourced from {@link + * EventListener#onStaticMetadataChanged(List)} and {@link MetadataOutput#onMetadata(Metadata)}. + * + * @param mediaMetadata The combined {@link MediaMetadata}. + */ + default void onMediaMetadataChanged(MediaMetadata mediaMetadata) {} + /** * Called when the player starts or stops loading the source. * diff --git a/library/common/src/main/java/com/google/android/exoplayer2/metadata/Metadata.java b/library/common/src/main/java/com/google/android/exoplayer2/metadata/Metadata.java index 0c038b2a72..01ae340609 100644 --- a/library/common/src/main/java/com/google/android/exoplayer2/metadata/Metadata.java +++ b/library/common/src/main/java/com/google/android/exoplayer2/metadata/Metadata.java @@ -51,6 +51,10 @@ public final class Metadata implements Parcelable { /** * Updates the {@link MediaMetadata.Builder} with the type specific values stored in this Entry. * + *

The order of the {@link Entry} objects in the {@link Metadata} matters. If two {@link + * Entry} entries attempt to populate the same {@link MediaMetadata} field, then the last one in + * the list is used. + * * @param builder The builder to be updated. */ default void populateMediaMetadata(MediaMetadata.Builder builder) {} diff --git a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java index 60a29f678c..6e1b434f52 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/SimpleExoPlayer.java @@ -2067,6 +2067,14 @@ 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, @@ -2242,6 +2250,7 @@ public class SimpleExoPlayer extends BasePlayer @Override public void onMetadata(Metadata metadata) { analyticsCollector.onMetadata(metadata); + setMediaMetadata(getMediaMetadata().buildUpon().populateFromMetadata(metadata).build()); for (MetadataOutput metadataOutput : metadataOutputs) { metadataOutput.onMetadata(metadata); } @@ -2371,6 +2380,16 @@ public class SimpleExoPlayer extends BasePlayer currentMediaMetadata = mediaItem == null ? MediaMetadata.EMPTY : mediaItem.mediaMetadata; } + @Override + public void onStaticMetadataChanged(List 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();