From 510f5edd1d8828d8bda7d8205a1d7ac264ffbcca Mon Sep 17 00:00:00 2001 From: bachinger Date: Mon, 16 Mar 2020 20:18:15 +0000 Subject: [PATCH] Remove cast media item PiperOrigin-RevId: 301224632 --- .../android/exoplayer2/castdemo/DemoUtil.java | 59 +++--- .../exoplayer2/castdemo/MainActivity.java | 11 +- .../exoplayer2/castdemo/PlayerManager.java | 78 +------- .../ext/cast/DefaultMediaItemConverter.java | 64 ++++--- .../exoplayer2/ext/cast/MediaItem.java | 175 ------------------ .../ext/cast/MediaItemConverter.java | 1 + .../cast/DefaultMediaItemConverterTest.java | 21 ++- .../exoplayer2/ext/cast/MediaItemTest.java | 86 --------- .../google/android/exoplayer2/MediaItem.java | 39 ++-- .../android/exoplayer2/MediaMetadata.java | 65 +++++++ .../android/exoplayer2/MediaItemTest.java | 11 ++ .../android/exoplayer2/MediaMetadataTest.java | 43 +++++ 12 files changed, 231 insertions(+), 422 deletions(-) delete mode 100644 extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/MediaItem.java delete mode 100644 extensions/cast/src/test/java/com/google/android/exoplayer2/ext/cast/MediaItemTest.java create mode 100644 library/core/src/main/java/com/google/android/exoplayer2/MediaMetadata.java create mode 100644 library/core/src/test/java/com/google/android/exoplayer2/MediaMetadataTest.java diff --git a/demos/cast/src/main/java/com/google/android/exoplayer2/castdemo/DemoUtil.java b/demos/cast/src/main/java/com/google/android/exoplayer2/castdemo/DemoUtil.java index dacdbfe616..68b9d05370 100644 --- a/demos/cast/src/main/java/com/google/android/exoplayer2/castdemo/DemoUtil.java +++ b/demos/cast/src/main/java/com/google/android/exoplayer2/castdemo/DemoUtil.java @@ -17,8 +17,8 @@ package com.google.android.exoplayer2.castdemo; import android.net.Uri; import com.google.android.exoplayer2.C; -import com.google.android.exoplayer2.ext.cast.MediaItem; -import com.google.android.exoplayer2.ext.cast.MediaItem.DrmConfiguration; +import com.google.android.exoplayer2.MediaItem; +import com.google.android.exoplayer2.MediaMetadata; import com.google.android.exoplayer2.util.MimeTypes; import java.util.ArrayList; import java.util.Collections; @@ -41,60 +41,53 @@ import java.util.List; // Clear content. samples.add( new MediaItem.Builder() - .setUri("https://storage.googleapis.com/wvmedia/clear/h264/tears/tears.mpd") - .setTitle("Clear DASH: Tears") + .setSourceUri("https://storage.googleapis.com/wvmedia/clear/h264/tears/tears.mpd") + .setMediaMetadata(new MediaMetadata.Builder().setTitle("Clear DASH: Tears").build()) .setMimeType(MIME_TYPE_DASH) .build()); samples.add( new MediaItem.Builder() - .setUri("https://storage.googleapis.com/shaka-demo-assets/angel-one-hls/hls.m3u8") - .setTitle("Clear HLS: Angel one") + .setSourceUri("https://storage.googleapis.com/shaka-demo-assets/angel-one-hls/hls.m3u8") + .setMediaMetadata(new MediaMetadata.Builder().setTitle("Clear HLS: Angel one").build()) .setMimeType(MIME_TYPE_HLS) .build()); samples.add( new MediaItem.Builder() - .setUri("https://html5demos.com/assets/dizzy.mp4") - .setTitle("Clear MP4: Dizzy") + .setSourceUri("https://html5demos.com/assets/dizzy.mp4") + .setMediaMetadata(new MediaMetadata.Builder().setTitle("Clear MP4: Dizzy").build()) .setMimeType(MIME_TYPE_VIDEO_MP4) .build()); // DRM content. samples.add( new MediaItem.Builder() - .setUri(Uri.parse("https://storage.googleapis.com/wvmedia/cenc/h264/tears/tears.mpd")) - .setTitle("Widevine DASH cenc: Tears") + .setSourceUri( + Uri.parse("https://storage.googleapis.com/wvmedia/cenc/h264/tears/tears.mpd")) + .setMediaMetadata( + new MediaMetadata.Builder().setTitle("Widevine DASH cenc: Tears").build()) .setMimeType(MIME_TYPE_DASH) - .setDrmConfiguration( - new DrmConfiguration( - C.WIDEVINE_UUID, - Uri.parse("https://proxy.uat.widevine.com/proxy?provider=widevine_test"), - Collections.emptyMap())) + .setDrmUuid(C.WIDEVINE_UUID) + .setDrmLicenseUri("https://proxy.uat.widevine.com/proxy?provider=widevine_test") .build()); samples.add( new MediaItem.Builder() - .setUri( - Uri.parse( - "https://storage.googleapis.com/wvmedia/cbc1/h264/tears/tears_aes_cbc1.mpd")) - .setTitle("Widevine DASH cbc1: Tears") + .setSourceUri( + "https://storage.googleapis.com/wvmedia/cbc1/h264/tears/tears_aes_cbc1.mpd") + .setMediaMetadata( + new MediaMetadata.Builder().setTitle("Widevine DASH cbc1: Tears").build()) .setMimeType(MIME_TYPE_DASH) - .setDrmConfiguration( - new DrmConfiguration( - C.WIDEVINE_UUID, - Uri.parse("https://proxy.uat.widevine.com/proxy?provider=widevine_test"), - Collections.emptyMap())) + .setDrmUuid(C.WIDEVINE_UUID) + .setDrmLicenseUri("https://proxy.uat.widevine.com/proxy?provider=widevine_test") .build()); samples.add( new MediaItem.Builder() - .setUri( - Uri.parse( - "https://storage.googleapis.com/wvmedia/cbcs/h264/tears/tears_aes_cbcs.mpd")) - .setTitle("Widevine DASH cbcs: Tears") + .setSourceUri( + "https://storage.googleapis.com/wvmedia/cbcs/h264/tears/tears_aes_cbcs.mpd") + .setMediaMetadata( + new MediaMetadata.Builder().setTitle("Widevine DASH cbcs: Tears").build()) .setMimeType(MIME_TYPE_DASH) - .setDrmConfiguration( - new DrmConfiguration( - C.WIDEVINE_UUID, - Uri.parse("https://proxy.uat.widevine.com/proxy?provider=widevine_test"), - Collections.emptyMap())) + .setDrmUuid(C.WIDEVINE_UUID) + .setDrmLicenseUri("https://proxy.uat.widevine.com/proxy?provider=widevine_test") .build()); SAMPLES = Collections.unmodifiableList(samples); diff --git a/demos/cast/src/main/java/com/google/android/exoplayer2/castdemo/MainActivity.java b/demos/cast/src/main/java/com/google/android/exoplayer2/castdemo/MainActivity.java index e144e61b62..cf8b02a515 100644 --- a/demos/cast/src/main/java/com/google/android/exoplayer2/castdemo/MainActivity.java +++ b/demos/cast/src/main/java/com/google/android/exoplayer2/castdemo/MainActivity.java @@ -37,10 +37,12 @@ import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView.ViewHolder; import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.MediaItem; import com.google.android.exoplayer2.SimpleExoPlayer; -import com.google.android.exoplayer2.ext.cast.MediaItem; import com.google.android.exoplayer2.ui.PlayerControlView; import com.google.android.exoplayer2.ui.PlayerView; +import com.google.android.exoplayer2.util.Assertions; +import com.google.android.exoplayer2.util.Util; import com.google.android.gms.cast.framework.CastButtonFactory; import com.google.android.gms.cast.framework.CastContext; import com.google.android.gms.dynamite.DynamiteModule; @@ -206,9 +208,10 @@ public class MainActivity extends AppCompatActivity @Override public void onBindViewHolder(QueueItemViewHolder holder, int position) { - holder.item = playerManager.getItem(position); + holder.item = Assertions.checkNotNull(playerManager.getItem(position)); + TextView view = holder.textView; - view.setText(holder.item.title); + view.setText(holder.item.mediaMetadata.title); // TODO: Solve coloring using the theme's ColorStateList. view.setTextColor( ColorUtils.setAlphaComponent( @@ -305,7 +308,7 @@ public class MainActivity extends AppCompatActivity @NonNull public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { View view = super.getView(position, convertView, parent); - ((TextView) view).setText(getItem(position).title); + ((TextView) view).setText(Util.castNonNull(getItem(position)).mediaMetadata.title); return view; } } diff --git a/demos/cast/src/main/java/com/google/android/exoplayer2/castdemo/PlayerManager.java b/demos/cast/src/main/java/com/google/android/exoplayer2/castdemo/PlayerManager.java index 5df10b5a7e..c3c4d60a47 100644 --- a/demos/cast/src/main/java/com/google/android/exoplayer2/castdemo/PlayerManager.java +++ b/demos/cast/src/main/java/com/google/android/exoplayer2/castdemo/PlayerManager.java @@ -16,11 +16,11 @@ package com.google.android.exoplayer2.castdemo; import android.content.Context; -import android.net.Uri; import android.view.KeyEvent; import android.view.View; import androidx.annotation.NonNull; import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.MediaItem; import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.Player.DiscontinuityReason; import com.google.android.exoplayer2.Player.EventListener; @@ -28,34 +28,22 @@ import com.google.android.exoplayer2.Player.TimelineChangeReason; import com.google.android.exoplayer2.SimpleExoPlayer; import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.Timeline.Period; -import com.google.android.exoplayer2.drm.DefaultDrmSessionManager; -import com.google.android.exoplayer2.drm.DrmSessionManager; -import com.google.android.exoplayer2.drm.ExoMediaCrypto; -import com.google.android.exoplayer2.drm.FrameworkMediaDrm; -import com.google.android.exoplayer2.drm.HttpMediaDrmCallback; import com.google.android.exoplayer2.ext.cast.CastPlayer; import com.google.android.exoplayer2.ext.cast.DefaultMediaItemConverter; -import com.google.android.exoplayer2.ext.cast.MediaItem; import com.google.android.exoplayer2.ext.cast.MediaItemConverter; import com.google.android.exoplayer2.ext.cast.SessionAvailabilityListener; import com.google.android.exoplayer2.source.ConcatenatingMediaSource; -import com.google.android.exoplayer2.source.MediaSource; -import com.google.android.exoplayer2.source.ProgressiveMediaSource; +import com.google.android.exoplayer2.source.DefaultMediaSourceFactory; import com.google.android.exoplayer2.source.TrackGroupArray; -import com.google.android.exoplayer2.source.dash.DashMediaSource; -import com.google.android.exoplayer2.source.hls.HlsMediaSource; -import com.google.android.exoplayer2.source.smoothstreaming.SsMediaSource; import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; import com.google.android.exoplayer2.trackselection.MappingTrackSelector; import com.google.android.exoplayer2.trackselection.TrackSelectionArray; import com.google.android.exoplayer2.ui.PlayerControlView; import com.google.android.exoplayer2.ui.PlayerView; import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory; -import com.google.android.exoplayer2.util.Util; import com.google.android.gms.cast.MediaQueueItem; import com.google.android.gms.cast.framework.CastContext; import java.util.ArrayList; -import java.util.Map; /** Manages players and an internal media queue for the demo app. */ /* package */ class PlayerManager implements EventListener, SessionAvailabilityListener { @@ -78,6 +66,7 @@ import java.util.Map; private static final DefaultHttpDataSourceFactory DATA_SOURCE_FACTORY = new DefaultHttpDataSourceFactory(USER_AGENT); + private final DefaultMediaSourceFactory defaultMediaSourceFactory; private final PlayerView localPlayerView; private final PlayerControlView castControlView; private final DefaultTrackSelector trackSelector; @@ -117,6 +106,7 @@ import java.util.Map; trackSelector = new DefaultTrackSelector(context); exoPlayer = new SimpleExoPlayer.Builder(context).setTrackSelector(trackSelector).build(); + defaultMediaSourceFactory = DefaultMediaSourceFactory.newInstance(context, DATA_SOURCE_FACTORY); exoPlayer.addListener(this); localPlayerView.setPlayer(exoPlayer); @@ -151,7 +141,7 @@ import java.util.Map; */ public void addItem(MediaItem item) { mediaQueue.add(item); - concatenatingMediaSource.addMediaSource(buildMediaSource(item)); + concatenatingMediaSource.addMediaSource(defaultMediaSourceFactory.createMediaSource(item)); if (currentPlayer == castPlayer) { castPlayer.addItems(mediaItemConverter.toMediaQueueItem(item)); } @@ -400,62 +390,4 @@ import java.util.Map; listener.onQueuePositionChanged(oldIndex, currentItemIndex); } } - - private MediaSource buildMediaSource(MediaItem item) { - Uri uri = item.uri; - String mimeType = item.mimeType; - if (mimeType == null) { - throw new IllegalArgumentException("mimeType is required"); - } - - DrmSessionManager drmSessionManager = - DrmSessionManager.getDummyDrmSessionManager(); - MediaItem.DrmConfiguration drmConfiguration = item.drmConfiguration; - if (drmConfiguration != null && Util.SDK_INT >= 18) { - String licenseServerUrl = - drmConfiguration.licenseUri != null ? drmConfiguration.licenseUri.toString() : ""; - HttpMediaDrmCallback drmCallback = - new HttpMediaDrmCallback(licenseServerUrl, DATA_SOURCE_FACTORY); - for (Map.Entry requestHeader : drmConfiguration.requestHeaders.entrySet()) { - drmCallback.setKeyRequestProperty(requestHeader.getKey(), requestHeader.getValue()); - } - drmSessionManager = - new DefaultDrmSessionManager.Builder() - .setMultiSession(/* multiSession= */ true) - .setUuidAndExoMediaDrmProvider( - drmConfiguration.uuid, FrameworkMediaDrm.DEFAULT_PROVIDER) - .build(drmCallback); - } - - MediaSource createdMediaSource; - switch (mimeType) { - case DemoUtil.MIME_TYPE_SS: - createdMediaSource = - new SsMediaSource.Factory(DATA_SOURCE_FACTORY) - .setDrmSessionManager(drmSessionManager) - .createMediaSource(uri); - break; - case DemoUtil.MIME_TYPE_DASH: - createdMediaSource = - new DashMediaSource.Factory(DATA_SOURCE_FACTORY) - .setDrmSessionManager(drmSessionManager) - .createMediaSource(uri); - break; - case DemoUtil.MIME_TYPE_HLS: - createdMediaSource = - new HlsMediaSource.Factory(DATA_SOURCE_FACTORY) - .setDrmSessionManager(drmSessionManager) - .createMediaSource(uri); - break; - case DemoUtil.MIME_TYPE_VIDEO_MP4: - createdMediaSource = - new ProgressiveMediaSource.Factory(DATA_SOURCE_FACTORY) - .setDrmSessionManager(drmSessionManager) - .createMediaSource(uri); - break; - default: - throw new IllegalArgumentException("mimeType is unsupported: " + mimeType); - } - return createdMediaSource; - } } diff --git a/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/DefaultMediaItemConverter.java b/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/DefaultMediaItemConverter.java index 098803a512..b3a4320a97 100644 --- a/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/DefaultMediaItemConverter.java +++ b/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/DefaultMediaItemConverter.java @@ -18,7 +18,8 @@ package com.google.android.exoplayer2.ext.cast; import android.net.Uri; import androidx.annotation.Nullable; import com.google.android.exoplayer2.C; -import com.google.android.exoplayer2.ext.cast.MediaItem.DrmConfiguration; +import com.google.android.exoplayer2.MediaItem; +import com.google.android.exoplayer2.util.Assertions; import com.google.android.gms.cast.MediaInfo; import com.google.android.gms.cast.MediaMetadata; import com.google.android.gms.cast.MediaQueueItem; @@ -48,17 +49,18 @@ public final class DefaultMediaItemConverter implements MediaItemConverter { @Override public MediaQueueItem toMediaQueueItem(MediaItem item) { - if (item.mimeType == null) { + Assertions.checkNotNull(item.playbackProperties); + if (item.playbackProperties.mimeType == null) { throw new IllegalArgumentException("The item must specify its mimeType"); } MediaMetadata metadata = new MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE); - if (item.title != null) { - metadata.putString(MediaMetadata.KEY_TITLE, item.title); + if (item.mediaMetadata.title != null) { + metadata.putString(MediaMetadata.KEY_TITLE, item.mediaMetadata.title); } MediaInfo mediaInfo = - new MediaInfo.Builder(item.uri.toString()) + new MediaInfo.Builder(item.playbackProperties.sourceUri.toString()) .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED) - .setContentType(item.mimeType) + .setContentType(item.playbackProperties.mimeType) .setMetadata(metadata) .setCustomData(getCustomData(item)) .build(); @@ -71,16 +73,19 @@ public final class DefaultMediaItemConverter implements MediaItemConverter { try { JSONObject mediaItemJson = customData.getJSONObject(KEY_MEDIA_ITEM); MediaItem.Builder builder = new MediaItem.Builder(); - builder.setUri(Uri.parse(mediaItemJson.getString(KEY_URI))); + builder.setSourceUri(Uri.parse(mediaItemJson.getString(KEY_URI))); if (mediaItemJson.has(KEY_TITLE)) { - builder.setTitle(mediaItemJson.getString(KEY_TITLE)); + com.google.android.exoplayer2.MediaMetadata mediaMetadata = + new com.google.android.exoplayer2.MediaMetadata.Builder() + .setTitle(mediaItemJson.getString(KEY_TITLE)) + .build(); + builder.setMediaMetadata(mediaMetadata); } if (mediaItemJson.has(KEY_MIME_TYPE)) { builder.setMimeType(mediaItemJson.getString(KEY_MIME_TYPE)); } if (mediaItemJson.has(KEY_DRM_CONFIGURATION)) { - builder.setDrmConfiguration( - getDrmConfiguration(mediaItemJson.getJSONObject(KEY_DRM_CONFIGURATION))); + populateDrmConfiguration(mediaItemJson.getJSONObject(KEY_DRM_CONFIGURATION), builder); } return builder.build(); } catch (JSONException e) { @@ -88,25 +93,26 @@ public final class DefaultMediaItemConverter implements MediaItemConverter { } } - private static DrmConfiguration getDrmConfiguration(JSONObject json) throws JSONException { - UUID uuid = UUID.fromString(json.getString(KEY_UUID)); - Uri licenseUri = Uri.parse(json.getString(KEY_LICENSE_URI)); + private static void populateDrmConfiguration(JSONObject json, MediaItem.Builder builder) + throws JSONException { + builder.setDrmUuid(UUID.fromString(json.getString(KEY_UUID))); + builder.setDrmLicenseUri(json.getString(KEY_LICENSE_URI)); JSONObject requestHeadersJson = json.getJSONObject(KEY_REQUEST_HEADERS); HashMap requestHeaders = new HashMap<>(); for (Iterator iterator = requestHeadersJson.keys(); iterator.hasNext(); ) { String key = iterator.next(); requestHeaders.put(key, requestHeadersJson.getString(key)); } - return new DrmConfiguration(uuid, licenseUri, requestHeaders); + builder.setDrmLicenseRequestHeaders(requestHeaders); } // Serialization. - private static JSONObject getCustomData(MediaItem item) { + private static JSONObject getCustomData(MediaItem mediaItem) { JSONObject json = new JSONObject(); try { - json.put(KEY_MEDIA_ITEM, getMediaItemJson(item)); - JSONObject playerConfigJson = getPlayerConfigJson(item); + json.put(KEY_MEDIA_ITEM, getMediaItemJson(mediaItem)); + @Nullable JSONObject playerConfigJson = getPlayerConfigJson(mediaItem); if (playerConfigJson != null) { json.put(KEY_PLAYER_CONFIG, playerConfigJson); } @@ -116,18 +122,21 @@ public final class DefaultMediaItemConverter implements MediaItemConverter { return json; } - private static JSONObject getMediaItemJson(MediaItem item) throws JSONException { + private static JSONObject getMediaItemJson(MediaItem mediaItem) throws JSONException { + Assertions.checkNotNull(mediaItem.playbackProperties); JSONObject json = new JSONObject(); - json.put(KEY_URI, item.uri.toString()); - json.put(KEY_TITLE, item.title); - json.put(KEY_MIME_TYPE, item.mimeType); - if (item.drmConfiguration != null) { - json.put(KEY_DRM_CONFIGURATION, getDrmConfigurationJson(item.drmConfiguration)); + json.put(KEY_TITLE, mediaItem.mediaMetadata.title); + json.put(KEY_URI, mediaItem.playbackProperties.sourceUri.toString()); + json.put(KEY_MIME_TYPE, mediaItem.playbackProperties.mimeType); + if (mediaItem.playbackProperties.drmConfiguration != null) { + json.put( + KEY_DRM_CONFIGURATION, + getDrmConfigurationJson(mediaItem.playbackProperties.drmConfiguration)); } return json; } - private static JSONObject getDrmConfigurationJson(DrmConfiguration drmConfiguration) + private static JSONObject getDrmConfigurationJson(MediaItem.DrmConfiguration drmConfiguration) throws JSONException { JSONObject json = new JSONObject(); json.put(KEY_UUID, drmConfiguration.uuid); @@ -137,11 +146,12 @@ public final class DefaultMediaItemConverter implements MediaItemConverter { } @Nullable - private static JSONObject getPlayerConfigJson(MediaItem item) throws JSONException { - DrmConfiguration drmConfiguration = item.drmConfiguration; - if (drmConfiguration == null) { + private static JSONObject getPlayerConfigJson(MediaItem mediaItem) throws JSONException { + if (mediaItem.playbackProperties == null + || mediaItem.playbackProperties.drmConfiguration == null) { return null; } + MediaItem.DrmConfiguration drmConfiguration = mediaItem.playbackProperties.drmConfiguration; String drmScheme; if (C.WIDEVINE_UUID.equals(drmConfiguration.uuid)) { diff --git a/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/MediaItem.java b/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/MediaItem.java deleted file mode 100644 index 7ac0da7078..0000000000 --- a/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/MediaItem.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.google.android.exoplayer2.ext.cast; - -import android.net.Uri; -import androidx.annotation.Nullable; -import com.google.android.exoplayer2.util.Assertions; -import com.google.android.exoplayer2.util.Util; -import java.util.Collections; -import java.util.Map; -import java.util.UUID; - -/** Representation of a media item. */ -public final class MediaItem { - - /** A builder for {@link MediaItem} instances. */ - public static final class Builder { - - @Nullable private Uri uri; - @Nullable private String title; - @Nullable private String mimeType; - @Nullable private DrmConfiguration drmConfiguration; - - /** See {@link MediaItem#uri}. */ - public Builder setUri(String uri) { - return setUri(Uri.parse(uri)); - } - - /** See {@link MediaItem#uri}. */ - public Builder setUri(Uri uri) { - this.uri = uri; - return this; - } - - /** See {@link MediaItem#title}. */ - public Builder setTitle(String title) { - this.title = title; - return this; - } - - /** See {@link MediaItem#mimeType}. */ - public Builder setMimeType(String mimeType) { - this.mimeType = mimeType; - return this; - } - - /** See {@link MediaItem#drmConfiguration}. */ - public Builder setDrmConfiguration(DrmConfiguration drmConfiguration) { - this.drmConfiguration = drmConfiguration; - return this; - } - - /** Returns a new {@link MediaItem} instance with the current builder values. */ - public MediaItem build() { - Assertions.checkNotNull(uri); - return new MediaItem(uri, title, mimeType, drmConfiguration); - } - } - - /** DRM configuration for a media item. */ - public static final class DrmConfiguration { - - /** The UUID of the protection scheme. */ - public final UUID uuid; - - /** - * Optional license server {@link Uri}. If {@code null} then the license server must be - * specified by the media. - */ - @Nullable public final Uri licenseUri; - - /** Headers that should be attached to any license requests. */ - public final Map requestHeaders; - - /** - * Creates an instance. - * - * @param uuid See {@link #uuid}. - * @param licenseUri See {@link #licenseUri}. - * @param requestHeaders See {@link #requestHeaders}. - */ - public DrmConfiguration( - UUID uuid, @Nullable Uri licenseUri, @Nullable Map requestHeaders) { - this.uuid = uuid; - this.licenseUri = licenseUri; - this.requestHeaders = - requestHeaders == null - ? Collections.emptyMap() - : Collections.unmodifiableMap(requestHeaders); - } - - @Override - public boolean equals(@Nullable Object obj) { - if (this == obj) { - return true; - } - if (obj == null || getClass() != obj.getClass()) { - return false; - } - - DrmConfiguration other = (DrmConfiguration) obj; - return uuid.equals(other.uuid) - && Util.areEqual(licenseUri, other.licenseUri) - && requestHeaders.equals(other.requestHeaders); - } - - @Override - public int hashCode() { - int result = uuid.hashCode(); - result = 31 * result + (licenseUri != null ? licenseUri.hashCode() : 0); - result = 31 * result + requestHeaders.hashCode(); - return result; - } - } - - /** The media {@link Uri}. */ - public final Uri uri; - - /** The title of the item, or {@code null} if unspecified. */ - @Nullable public final String title; - - /** The mime type for the media, or {@code null} if unspecified. */ - @Nullable public final String mimeType; - - /** Optional {@link DrmConfiguration} for the media. */ - @Nullable public final DrmConfiguration drmConfiguration; - - private MediaItem( - Uri uri, - @Nullable String title, - @Nullable String mimeType, - @Nullable DrmConfiguration drmConfiguration) { - this.uri = uri; - this.title = title; - this.mimeType = mimeType; - this.drmConfiguration = drmConfiguration; - } - - @Override - public boolean equals(@Nullable Object obj) { - if (this == obj) { - return true; - } - if (obj == null || getClass() != obj.getClass()) { - return false; - } - MediaItem other = (MediaItem) obj; - return uri.equals(other.uri) - && Util.areEqual(title, other.title) - && Util.areEqual(mimeType, other.mimeType) - && Util.areEqual(drmConfiguration, other.drmConfiguration); - } - - @Override - public int hashCode() { - int result = uri.hashCode(); - result = 31 * result + (title == null ? 0 : title.hashCode()); - result = 31 * result + (drmConfiguration == null ? 0 : drmConfiguration.hashCode()); - result = 31 * result + (mimeType == null ? 0 : mimeType.hashCode()); - return result; - } -} diff --git a/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/MediaItemConverter.java b/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/MediaItemConverter.java index 23633aa4d2..c4a5184632 100644 --- a/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/MediaItemConverter.java +++ b/extensions/cast/src/main/java/com/google/android/exoplayer2/ext/cast/MediaItemConverter.java @@ -15,6 +15,7 @@ */ package com.google.android.exoplayer2.ext.cast; +import com.google.android.exoplayer2.MediaItem; import com.google.android.gms.cast.MediaQueueItem; /** Converts between {@link MediaItem} and the Cast SDK's {@link MediaQueueItem}. */ diff --git a/extensions/cast/src/test/java/com/google/android/exoplayer2/ext/cast/DefaultMediaItemConverterTest.java b/extensions/cast/src/test/java/com/google/android/exoplayer2/ext/cast/DefaultMediaItemConverterTest.java index cf9b9d3496..fc1413ae66 100644 --- a/extensions/cast/src/test/java/com/google/android/exoplayer2/ext/cast/DefaultMediaItemConverterTest.java +++ b/extensions/cast/src/test/java/com/google/android/exoplayer2/ext/cast/DefaultMediaItemConverterTest.java @@ -20,7 +20,9 @@ import static com.google.common.truth.Truth.assertThat; import android.net.Uri; import androidx.test.ext.junit.runners.AndroidJUnit4; import com.google.android.exoplayer2.C; -import com.google.android.exoplayer2.ext.cast.MediaItem.DrmConfiguration; +import com.google.android.exoplayer2.MediaItem; +import com.google.android.exoplayer2.MediaMetadata; +import com.google.android.exoplayer2.util.MimeTypes; import com.google.android.gms.cast.MediaQueueItem; import java.util.Collections; import org.junit.Test; @@ -33,7 +35,8 @@ public class DefaultMediaItemConverterTest { @Test public void serialize_deserialize_minimal() { MediaItem.Builder builder = new MediaItem.Builder(); - MediaItem item = builder.setUri(Uri.parse("http://example.com")).setMimeType("mime").build(); + MediaItem item = + builder.setSourceUri("http://example.com").setMimeType(MimeTypes.APPLICATION_MPD).build(); DefaultMediaItemConverter converter = new DefaultMediaItemConverter(); MediaQueueItem queueItem = converter.toMediaQueueItem(item); @@ -47,14 +50,12 @@ public class DefaultMediaItemConverterTest { MediaItem.Builder builder = new MediaItem.Builder(); MediaItem item = builder - .setUri(Uri.parse("http://example.com")) - .setTitle("title") - .setMimeType("mime") - .setDrmConfiguration( - new DrmConfiguration( - C.WIDEVINE_UUID, - Uri.parse("http://license.com"), - Collections.singletonMap("key", "value"))) + .setSourceUri(Uri.parse("http://example.com")) + .setMediaMetadata(new MediaMetadata.Builder().build()) + .setMimeType(MimeTypes.APPLICATION_MPD) + .setDrmUuid(C.WIDEVINE_UUID) + .setDrmLicenseUri("http://license.com") + .setDrmLicenseRequestHeaders(Collections.singletonMap("key", "value")) .build(); DefaultMediaItemConverter converter = new DefaultMediaItemConverter(); diff --git a/extensions/cast/src/test/java/com/google/android/exoplayer2/ext/cast/MediaItemTest.java b/extensions/cast/src/test/java/com/google/android/exoplayer2/ext/cast/MediaItemTest.java deleted file mode 100644 index 7b410a8fbc..0000000000 --- a/extensions/cast/src/test/java/com/google/android/exoplayer2/ext/cast/MediaItemTest.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.google.android.exoplayer2.ext.cast; - -import static com.google.common.truth.Truth.assertThat; - -import android.net.Uri; -import androidx.test.ext.junit.runners.AndroidJUnit4; -import com.google.android.exoplayer2.C; -import com.google.android.exoplayer2.util.MimeTypes; -import java.util.HashMap; -import org.junit.Test; -import org.junit.runner.RunWith; - -/** Test for {@link MediaItem}. */ -@RunWith(AndroidJUnit4.class) -public class MediaItemTest { - - @Test - public void buildMediaItem_doesNotChangeState() { - MediaItem.Builder builder = new MediaItem.Builder(); - MediaItem item1 = - builder - .setUri(Uri.parse("http://example.com")) - .setTitle("title") - .setMimeType(MimeTypes.AUDIO_MP4) - .build(); - MediaItem item2 = builder.build(); - assertThat(item1).isEqualTo(item2); - } - - @Test - public void equals_withEqualDrmSchemes_returnsTrue() { - MediaItem.Builder builder1 = new MediaItem.Builder(); - MediaItem mediaItem1 = - builder1 - .setUri(Uri.parse("www.google.com")) - .setDrmConfiguration(buildDrmConfiguration(1)) - .build(); - MediaItem.Builder builder2 = new MediaItem.Builder(); - MediaItem mediaItem2 = - builder2 - .setUri(Uri.parse("www.google.com")) - .setDrmConfiguration(buildDrmConfiguration(1)) - .build(); - assertThat(mediaItem1).isEqualTo(mediaItem2); - } - - @Test - public void equals_withDifferentDrmRequestHeaders_returnsFalse() { - MediaItem.Builder builder1 = new MediaItem.Builder(); - MediaItem mediaItem1 = - builder1 - .setUri(Uri.parse("www.google.com")) - .setDrmConfiguration(buildDrmConfiguration(1)) - .build(); - MediaItem.Builder builder2 = new MediaItem.Builder(); - MediaItem mediaItem2 = - builder2 - .setUri(Uri.parse("www.google.com")) - .setDrmConfiguration(buildDrmConfiguration(2)) - .build(); - assertThat(mediaItem1).isNotEqualTo(mediaItem2); - } - - private static MediaItem.DrmConfiguration buildDrmConfiguration(int seed) { - HashMap requestHeaders = new HashMap<>(); - requestHeaders.put("key1", "value1"); - requestHeaders.put("key2", "value2" + seed); - return new MediaItem.DrmConfiguration( - C.WIDEVINE_UUID, Uri.parse("www.uri1.com"), requestHeaders); - } -} diff --git a/library/core/src/main/java/com/google/android/exoplayer2/MediaItem.java b/library/core/src/main/java/com/google/android/exoplayer2/MediaItem.java index e2440983a9..1d624c24f5 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/MediaItem.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/MediaItem.java @@ -62,6 +62,7 @@ public final class MediaItem { private boolean drmMultiSession; private List streamKeys; @Nullable private Object tag; + @Nullable private MediaMetadata mediaMetadata; /** Creates a builder. */ public Builder() { @@ -199,6 +200,12 @@ public final class MediaItem { return this; } + /** Sets the media metadata. */ + public Builder setMediaMetadata(MediaMetadata mediaMetadata) { + this.mediaMetadata = mediaMetadata; + return this; + } + /** * Returns a new {@link MediaItem} instance with the current builder values. */ @@ -218,7 +225,10 @@ public final class MediaItem { tag); mediaId = mediaId != null ? mediaId : sourceUri.toString(); } - return new MediaItem(Assertions.checkNotNull(mediaId), playbackProperties); + return new MediaItem( + Assertions.checkNotNull(mediaId), + playbackProperties, + mediaMetadata != null ? mediaMetadata : new MediaMetadata.Builder().build()); } } @@ -240,15 +250,7 @@ public final class MediaItem { /** Whether the drm configuration is multi session enabled. */ public final boolean multiSession; - /** - * Creates an instance. - * - * @param uuid See {@link #uuid}. - * @param licenseUri See {@link #licenseUri}. - * @param requestHeaders See {@link #requestHeaders}. - * @param multiSession See {@link #multiSession}. - */ - public DrmConfiguration( + private DrmConfiguration( UUID uuid, @Nullable Uri licenseUri, Map requestHeaders, @@ -312,7 +314,7 @@ public final class MediaItem { */ @Nullable public final Object tag; - public PlaybackProperties( + private PlaybackProperties( Uri sourceUri, @Nullable String mimeType, @Nullable DrmConfiguration drmConfiguration, @@ -356,12 +358,19 @@ public final class MediaItem { /** Identifies the media item. */ public final String mediaId; - /** Optional playback properties. */ + /** Optional playback properties. Maybe be {@code null} if shared over process boundaries. */ @Nullable public final PlaybackProperties playbackProperties; - private MediaItem(String mediaId, @Nullable PlaybackProperties playbackProperties) { + /** The media metadata. */ + public final MediaMetadata mediaMetadata; + + private MediaItem( + String mediaId, + @Nullable PlaybackProperties playbackProperties, + MediaMetadata mediaMetadata) { this.mediaId = mediaId; this.playbackProperties = playbackProperties; + this.mediaMetadata = mediaMetadata; } @Override @@ -376,13 +385,15 @@ public final class MediaItem { MediaItem other = (MediaItem) o; return Util.areEqual(mediaId, other.mediaId) - && Util.areEqual(playbackProperties, other.playbackProperties); + && Util.areEqual(playbackProperties, other.playbackProperties) + && Util.areEqual(mediaMetadata, other.mediaMetadata); } @Override public int hashCode() { int result = mediaId.hashCode(); result = 31 * result + (playbackProperties != null ? playbackProperties.hashCode() : 0); + result = 31 * result + mediaMetadata.hashCode(); return result; } } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/MediaMetadata.java b/library/core/src/main/java/com/google/android/exoplayer2/MediaMetadata.java new file mode 100644 index 0000000000..37fb8fcb0d --- /dev/null +++ b/library/core/src/main/java/com/google/android/exoplayer2/MediaMetadata.java @@ -0,0 +1,65 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2; + +import androidx.annotation.Nullable; +import com.google.android.exoplayer2.util.Util; + +/** Metadata of the {@link MediaItem}. */ +public final class MediaMetadata { + + /** A builder for {@link MediaMetadata} instances. */ + public static final class Builder { + + @Nullable private String title; + + /** Sets the optional title. */ + public Builder setTitle(@Nullable String title) { + this.title = title; + return this; + } + + /** Returns a new {@link MediaMetadata} instance with the current builder values. */ + public MediaMetadata build() { + return new MediaMetadata(title); + } + } + + /** Optional title. */ + @Nullable public final String title; + + private MediaMetadata(@Nullable String title) { + this.title = title; + } + + @Override + public boolean equals(@Nullable Object obj) { + if (this == obj) { + return true; + } + if (obj == null || getClass() != obj.getClass()) { + return false; + } + MediaMetadata other = (MediaMetadata) obj; + + return Util.areEqual(title, other.title); + } + + @Override + public int hashCode() { + return title == null ? 0 : title.hashCode(); + } +} diff --git a/library/core/src/test/java/com/google/android/exoplayer2/MediaItemTest.java b/library/core/src/test/java/com/google/android/exoplayer2/MediaItemTest.java index 1cb5f204f4..94c4945689 100644 --- a/library/core/src/test/java/com/google/android/exoplayer2/MediaItemTest.java +++ b/library/core/src/test/java/com/google/android/exoplayer2/MediaItemTest.java @@ -48,6 +48,7 @@ public class MediaItemTest { assertThat(mediaItem.playbackProperties.sourceUri.toString()).isEqualTo(URI_STRING); assertThat(mediaItem.mediaId).isEqualTo(URI_STRING); + assertThat(mediaItem.mediaMetadata).isNotNull(); } @Test @@ -144,4 +145,14 @@ public class MediaItemTest { assertThat(mediaItem.playbackProperties.tag).isEqualTo(tag); } + + @Test + public void builderSetMediaMetadata_setsMetadata() { + MediaMetadata mediaMetadata = new MediaMetadata.Builder().setTitle("title").build(); + + MediaItem mediaItem = + new MediaItem.Builder().setSourceUri(URI_STRING).setMediaMetadata(mediaMetadata).build(); + + assertThat(mediaItem.mediaMetadata).isEqualTo(mediaMetadata); + } } diff --git a/library/core/src/test/java/com/google/android/exoplayer2/MediaMetadataTest.java b/library/core/src/test/java/com/google/android/exoplayer2/MediaMetadataTest.java new file mode 100644 index 0000000000..43d5bc5a2c --- /dev/null +++ b/library/core/src/test/java/com/google/android/exoplayer2/MediaMetadataTest.java @@ -0,0 +1,43 @@ +/* + * Copyright 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.android.exoplayer2; + +import static com.google.common.truth.Truth.assertThat; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** Unit test for {@link MediaMetadata}. */ +@RunWith(AndroidJUnit4.class) +public class MediaMetadataTest { + + @Test + public void builder_minimal_correctDefaults() { + MediaMetadata mediaMetadata = new MediaMetadata.Builder().build(); + + assertThat(mediaMetadata.title).isNull(); + } + + @Test + public void builderSetTitle_setsTitle() { + String title = "title"; + + MediaMetadata mediaMetadata = new MediaMetadata.Builder().setTitle(title).build(); + + assertThat(mediaMetadata.title).isEqualTo(title); + } +}