Cast: Simplify MediaItem/Sample to a single MediaItem class
PiperOrigin-RevId: 260021990
This commit is contained in:
parent
1b9e2497ff
commit
596be3b71b
@ -15,97 +15,49 @@
|
|||||||
*/
|
*/
|
||||||
package com.google.android.exoplayer2.castdemo;
|
package com.google.android.exoplayer2.castdemo;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import android.net.Uri;
|
||||||
import com.google.android.exoplayer2.C;
|
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.util.MimeTypes;
|
import com.google.android.exoplayer2.util.MimeTypes;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
/** Utility methods and constants for the Cast demo application. */
|
/** Utility methods and constants for the Cast demo application. */
|
||||||
/* package */ final class DemoUtil {
|
/* package */ final class DemoUtil {
|
||||||
|
|
||||||
/** Represents a media sample. */
|
|
||||||
public static final class Sample {
|
|
||||||
|
|
||||||
/** The URI of the media content. */
|
|
||||||
public final String uri;
|
|
||||||
/** The name of the sample. */
|
|
||||||
public final String name;
|
|
||||||
/** The mime type of the sample media content. */
|
|
||||||
public final String mimeType;
|
|
||||||
/** Data to configure DRM license acquisition. May be null if content is not DRM-protected. */
|
|
||||||
@Nullable public final DrmConfiguration drmConfiguration;
|
|
||||||
|
|
||||||
public Sample(String uri, String name, String mimeType) {
|
|
||||||
this(uri, name, mimeType, /* drmConfiguration= */ null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Sample(
|
|
||||||
String uri, String name, String mimeType, @Nullable DrmConfiguration drmConfiguration) {
|
|
||||||
this.uri = uri;
|
|
||||||
this.name = name;
|
|
||||||
this.mimeType = mimeType;
|
|
||||||
this.drmConfiguration = drmConfiguration;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Holds information required to play DRM-protected content. */
|
|
||||||
public static final class DrmConfiguration {
|
|
||||||
|
|
||||||
/** The {@link UUID} of the DRM scheme that protects the content. */
|
|
||||||
public final UUID drmSchemeUuid;
|
|
||||||
/**
|
|
||||||
* The URI from which players should obtain DRM licenses. May be null if the license server URI
|
|
||||||
* is provided as part of the media.
|
|
||||||
*/
|
|
||||||
@Nullable public final String licenseServerUri;
|
|
||||||
/** HTTP request headers to include the in DRM license requests. */
|
|
||||||
public final Map<String, String> httpRequestHeaders;
|
|
||||||
|
|
||||||
public DrmConfiguration(
|
|
||||||
UUID drmSchemeUuid,
|
|
||||||
@Nullable String licenseServerUri,
|
|
||||||
Map<String, String> httpRequestHeaders) {
|
|
||||||
this.drmSchemeUuid = drmSchemeUuid;
|
|
||||||
this.licenseServerUri = licenseServerUri;
|
|
||||||
this.httpRequestHeaders = httpRequestHeaders;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final String MIME_TYPE_DASH = MimeTypes.APPLICATION_MPD;
|
public static final String MIME_TYPE_DASH = MimeTypes.APPLICATION_MPD;
|
||||||
public static final String MIME_TYPE_HLS = MimeTypes.APPLICATION_M3U8;
|
public static final String MIME_TYPE_HLS = MimeTypes.APPLICATION_M3U8;
|
||||||
public static final String MIME_TYPE_SS = MimeTypes.APPLICATION_SS;
|
public static final String MIME_TYPE_SS = MimeTypes.APPLICATION_SS;
|
||||||
public static final String MIME_TYPE_VIDEO_MP4 = MimeTypes.VIDEO_MP4;
|
public static final String MIME_TYPE_VIDEO_MP4 = MimeTypes.VIDEO_MP4;
|
||||||
|
|
||||||
/** The list of samples available in the cast demo app. */
|
/** The list of samples available in the cast demo app. */
|
||||||
public static final List<Sample> SAMPLES;
|
public static final List<MediaItem> SAMPLES;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
// App samples.
|
// App samples.
|
||||||
ArrayList<Sample> samples = new ArrayList<>();
|
ArrayList<MediaItem> samples = new ArrayList<>();
|
||||||
|
|
||||||
// Clear content.
|
// Clear content.
|
||||||
samples.add(
|
samples.add(
|
||||||
new Sample(
|
new MediaItem.Builder()
|
||||||
"https://storage.googleapis.com/wvmedia/clear/h264/tears/tears.mpd",
|
.setUri("https://storage.googleapis.com/wvmedia/clear/h264/tears/tears.mpd")
|
||||||
"Clear DASH: Tears",
|
.setTitle("Clear DASH: Tears")
|
||||||
MIME_TYPE_DASH));
|
.setMimeType(MIME_TYPE_DASH)
|
||||||
|
.build());
|
||||||
samples.add(
|
samples.add(
|
||||||
new Sample(
|
new MediaItem.Builder()
|
||||||
"https://storage.googleapis.com/shaka-demo-assets/angel-one-hls/hls.m3u8",
|
.setUri("https://storage.googleapis.com/shaka-demo-assets/angel-one-hls/hls.m3u8")
|
||||||
"Clear HLS: Angel one",
|
.setTitle("Clear HLS: Angel one")
|
||||||
MIME_TYPE_HLS));
|
.setMimeType(MIME_TYPE_HLS)
|
||||||
|
.build());
|
||||||
samples.add(
|
samples.add(
|
||||||
new Sample(
|
new MediaItem.Builder()
|
||||||
"https://html5demos.com/assets/dizzy.mp4", "Clear MP4: Dizzy", MIME_TYPE_VIDEO_MP4));
|
.setUri("https://html5demos.com/assets/dizzy.mp4")
|
||||||
|
.setTitle("Clear MP4: Dizzy")
|
||||||
|
.setMimeType(MIME_TYPE_VIDEO_MP4)
|
||||||
|
.build());
|
||||||
|
|
||||||
SAMPLES = Collections.unmodifiableList(samples);
|
SAMPLES = Collections.unmodifiableList(samples);
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,6 @@
|
|||||||
package com.google.android.exoplayer2.castdemo;
|
package com.google.android.exoplayer2.castdemo;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.net.Uri;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import androidx.core.graphics.ColorUtils;
|
import androidx.core.graphics.ColorUtils;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
@ -42,7 +41,6 @@ import com.google.android.exoplayer2.ui.PlayerView;
|
|||||||
import com.google.android.gms.cast.framework.CastButtonFactory;
|
import com.google.android.gms.cast.framework.CastButtonFactory;
|
||||||
import com.google.android.gms.cast.framework.CastContext;
|
import com.google.android.gms.cast.framework.CastContext;
|
||||||
import com.google.android.gms.dynamite.DynamiteModule;
|
import com.google.android.gms.dynamite.DynamiteModule;
|
||||||
import java.util.Collections;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An activity that plays video using {@link SimpleExoPlayer} and supports casting using ExoPlayer's
|
* An activity that plays video using {@link SimpleExoPlayer} and supports casting using ExoPlayer's
|
||||||
@ -172,25 +170,7 @@ public class MainActivity extends AppCompatActivity
|
|||||||
sampleList.setAdapter(new SampleListAdapter(this));
|
sampleList.setAdapter(new SampleListAdapter(this));
|
||||||
sampleList.setOnItemClickListener(
|
sampleList.setOnItemClickListener(
|
||||||
(parent, view, position, id) -> {
|
(parent, view, position, id) -> {
|
||||||
DemoUtil.Sample sample = DemoUtil.SAMPLES.get(position);
|
playerManager.addItem(DemoUtil.SAMPLES.get(position));
|
||||||
MediaItem.Builder mediaItemBuilder =
|
|
||||||
new MediaItem.Builder()
|
|
||||||
.setMedia(sample.uri)
|
|
||||||
.setTitle(sample.name)
|
|
||||||
.setMimeType(sample.mimeType);
|
|
||||||
DemoUtil.DrmConfiguration drmConfiguration = sample.drmConfiguration;
|
|
||||||
if (drmConfiguration != null) {
|
|
||||||
mediaItemBuilder.setDrmSchemes(
|
|
||||||
Collections.singletonList(
|
|
||||||
new MediaItem.DrmScheme(
|
|
||||||
drmConfiguration.drmSchemeUuid,
|
|
||||||
new MediaItem.UriBundle(
|
|
||||||
drmConfiguration.licenseServerUri != null
|
|
||||||
? Uri.parse(drmConfiguration.licenseServerUri)
|
|
||||||
: Uri.EMPTY,
|
|
||||||
drmConfiguration.httpRequestHeaders))));
|
|
||||||
}
|
|
||||||
playerManager.addItem(mediaItemBuilder.build());
|
|
||||||
mediaQueueListAdapter.notifyItemInserted(playerManager.getMediaQueueSize() - 1);
|
mediaQueueListAdapter.notifyItemInserted(playerManager.getMediaQueueSize() - 1);
|
||||||
});
|
});
|
||||||
return dialogList;
|
return dialogList;
|
||||||
@ -213,7 +193,9 @@ public class MainActivity extends AppCompatActivity
|
|||||||
TextView view = holder.textView;
|
TextView view = holder.textView;
|
||||||
view.setText(holder.item.title);
|
view.setText(holder.item.title);
|
||||||
// TODO: Solve coloring using the theme's ColorStateList.
|
// TODO: Solve coloring using the theme's ColorStateList.
|
||||||
view.setTextColor(ColorUtils.setAlphaComponent(view.getCurrentTextColor(),
|
view.setTextColor(
|
||||||
|
ColorUtils.setAlphaComponent(
|
||||||
|
view.getCurrentTextColor(),
|
||||||
position == playerManager.getCurrentItemIndex() ? 255 : 100));
|
position == playerManager.getCurrentItemIndex() ? 255 : 100));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -294,11 +276,10 @@ public class MainActivity extends AppCompatActivity
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class SampleListAdapter extends ArrayAdapter<DemoUtil.Sample> {
|
private static final class SampleListAdapter extends ArrayAdapter<MediaItem> {
|
||||||
|
|
||||||
public SampleListAdapter(Context context) {
|
public SampleListAdapter(Context context) {
|
||||||
super(context, android.R.layout.simple_list_item_1, DemoUtil.SAMPLES);
|
super(context, android.R.layout.simple_list_item_1, DemoUtil.SAMPLES);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -44,7 +44,6 @@ import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
|||||||
import com.google.android.exoplayer2.ui.PlayerControlView;
|
import com.google.android.exoplayer2.ui.PlayerControlView;
|
||||||
import com.google.android.exoplayer2.ui.PlayerView;
|
import com.google.android.exoplayer2.ui.PlayerView;
|
||||||
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory;
|
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory;
|
||||||
import com.google.android.exoplayer2.util.Assertions;
|
|
||||||
import com.google.android.gms.cast.MediaInfo;
|
import com.google.android.gms.cast.MediaInfo;
|
||||||
import com.google.android.gms.cast.MediaMetadata;
|
import com.google.android.gms.cast.MediaMetadata;
|
||||||
import com.google.android.gms.cast.MediaQueueItem;
|
import com.google.android.gms.cast.MediaQueueItem;
|
||||||
@ -368,8 +367,12 @@ import org.json.JSONObject;
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static MediaSource buildMediaSource(MediaItem item) {
|
private static MediaSource buildMediaSource(MediaItem item) {
|
||||||
Uri uri = item.media.uri;
|
Uri uri = item.uri;
|
||||||
switch (item.mimeType) {
|
String mimeType = item.mimeType;
|
||||||
|
if (mimeType == null) {
|
||||||
|
throw new IllegalArgumentException("mimeType is required");
|
||||||
|
}
|
||||||
|
switch (mimeType) {
|
||||||
case DemoUtil.MIME_TYPE_SS:
|
case DemoUtil.MIME_TYPE_SS:
|
||||||
return new SsMediaSource.Factory(DATA_SOURCE_FACTORY).createMediaSource(uri);
|
return new SsMediaSource.Factory(DATA_SOURCE_FACTORY).createMediaSource(uri);
|
||||||
case DemoUtil.MIME_TYPE_DASH:
|
case DemoUtil.MIME_TYPE_DASH:
|
||||||
@ -379,7 +382,7 @@ import org.json.JSONObject;
|
|||||||
case DemoUtil.MIME_TYPE_VIDEO_MP4:
|
case DemoUtil.MIME_TYPE_VIDEO_MP4:
|
||||||
return new ProgressiveMediaSource.Factory(DATA_SOURCE_FACTORY).createMediaSource(uri);
|
return new ProgressiveMediaSource.Factory(DATA_SOURCE_FACTORY).createMediaSource(uri);
|
||||||
default:
|
default:
|
||||||
throw new IllegalStateException("Unsupported type: " + item.mimeType);
|
throw new IllegalArgumentException("mimeType is unsupported: " + mimeType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -387,18 +390,18 @@ import org.json.JSONObject;
|
|||||||
MediaMetadata movieMetadata = new MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE);
|
MediaMetadata movieMetadata = new MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE);
|
||||||
movieMetadata.putString(MediaMetadata.KEY_TITLE, item.title);
|
movieMetadata.putString(MediaMetadata.KEY_TITLE, item.title);
|
||||||
MediaInfo.Builder mediaInfoBuilder =
|
MediaInfo.Builder mediaInfoBuilder =
|
||||||
new MediaInfo.Builder(item.media.uri.toString())
|
new MediaInfo.Builder(item.uri.toString())
|
||||||
.setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
|
.setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
|
||||||
.setContentType(item.mimeType)
|
.setContentType(item.mimeType)
|
||||||
.setMetadata(movieMetadata);
|
.setMetadata(movieMetadata);
|
||||||
if (!item.drmSchemes.isEmpty()) {
|
MediaItem.DrmConfiguration drmConfiguration = item.drmConfiguration;
|
||||||
MediaItem.DrmScheme scheme = item.drmSchemes.get(0);
|
if (drmConfiguration != null) {
|
||||||
try {
|
try {
|
||||||
// This configuration is only intended for testing and should *not* be used in production
|
// This configuration is only intended for testing and should *not* be used in production
|
||||||
// environments. See comment in the Cast Demo app's options provider.
|
// environments. See comment in the Cast Demo app's options provider.
|
||||||
JSONObject drmConfiguration = getDrmConfigurationJson(scheme);
|
JSONObject drmConfigurationJson = getDrmConfigurationJson(drmConfiguration);
|
||||||
if (drmConfiguration != null) {
|
if (drmConfigurationJson != null) {
|
||||||
mediaInfoBuilder.setCustomData(drmConfiguration);
|
mediaInfoBuilder.setCustomData(drmConfigurationJson);
|
||||||
}
|
}
|
||||||
} catch (JSONException e) {
|
} catch (JSONException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
@ -408,24 +411,23 @@ import org.json.JSONObject;
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private static JSONObject getDrmConfigurationJson(MediaItem.DrmScheme scheme)
|
private static JSONObject getDrmConfigurationJson(MediaItem.DrmConfiguration drmConfiguration)
|
||||||
throws JSONException {
|
throws JSONException {
|
||||||
String drmScheme;
|
String drmScheme;
|
||||||
if (C.WIDEVINE_UUID.equals(scheme.uuid)) {
|
if (C.WIDEVINE_UUID.equals(drmConfiguration.uuid)) {
|
||||||
drmScheme = "widevine";
|
drmScheme = "widevine";
|
||||||
} else if (C.PLAYREADY_UUID.equals(scheme.uuid)) {
|
} else if (C.PLAYREADY_UUID.equals(drmConfiguration.uuid)) {
|
||||||
drmScheme = "playready";
|
drmScheme = "playready";
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
MediaItem.UriBundle licenseServer = Assertions.checkNotNull(scheme.licenseServer);
|
|
||||||
JSONObject exoplayerConfig =
|
JSONObject exoplayerConfig =
|
||||||
new JSONObject().put("withCredentials", false).put("protectionSystem", drmScheme);
|
new JSONObject().put("withCredentials", false).put("protectionSystem", drmScheme);
|
||||||
if (!licenseServer.uri.equals(Uri.EMPTY)) {
|
if (drmConfiguration.licenseUri != null) {
|
||||||
exoplayerConfig.put("licenseUrl", licenseServer.uri.toString());
|
exoplayerConfig.put("licenseUrl", drmConfiguration.licenseUri);
|
||||||
}
|
}
|
||||||
if (!licenseServer.requestHeaders.isEmpty()) {
|
if (!drmConfiguration.requestHeaders.isEmpty()) {
|
||||||
exoplayerConfig.put("headers", new JSONObject(licenseServer.requestHeaders));
|
exoplayerConfig.put("headers", new JSONObject(drmConfiguration.requestHeaders));
|
||||||
}
|
}
|
||||||
return new JSONObject().put("exoPlayerConfig", exoplayerConfig);
|
return new JSONObject().put("exoPlayerConfig", exoplayerConfig);
|
||||||
}
|
}
|
||||||
|
@ -17,30 +17,32 @@ package com.google.android.exoplayer2.ext.cast;
|
|||||||
|
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
import com.google.android.exoplayer2.util.Assertions;
|
||||||
import com.google.android.exoplayer2.util.Util;
|
import com.google.android.exoplayer2.util.Util;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
/** Representation of an item that can be played by a media player. */
|
/** Representation of a media item. */
|
||||||
public final class MediaItem {
|
public final class MediaItem {
|
||||||
|
|
||||||
/** A builder for {@link MediaItem} instances. */
|
/** A builder for {@link MediaItem} instances. */
|
||||||
public static final class Builder {
|
public static final class Builder {
|
||||||
|
|
||||||
private String title;
|
@Nullable private Uri uri;
|
||||||
private MediaItem.UriBundle media;
|
@Nullable private String title;
|
||||||
private List<MediaItem.DrmScheme> drmSchemes;
|
@Nullable private String mimeType;
|
||||||
private String mimeType;
|
@Nullable private DrmConfiguration drmConfiguration;
|
||||||
|
|
||||||
public Builder() {
|
/** See {@link MediaItem#uri}. */
|
||||||
title = "";
|
public Builder setUri(String uri) {
|
||||||
media = UriBundle.EMPTY;
|
return setUri(Uri.parse(uri));
|
||||||
drmSchemes = Collections.emptyList();
|
}
|
||||||
mimeType = "";
|
|
||||||
|
/** See {@link MediaItem#uri}. */
|
||||||
|
public Builder setUri(Uri uri) {
|
||||||
|
this.uri = uri;
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** See {@link MediaItem#title}. */
|
/** See {@link MediaItem#title}. */
|
||||||
@ -49,194 +51,125 @@ public final class MediaItem {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Equivalent to {@link #setMedia(UriBundle) setMedia(new UriBundle(Uri.parse(uri)))}. */
|
|
||||||
public Builder setMedia(String uri) {
|
|
||||||
return setMedia(new UriBundle(Uri.parse(uri)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/** See {@link MediaItem#media}. */
|
|
||||||
public Builder setMedia(UriBundle media) {
|
|
||||||
this.media = media;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** See {@link MediaItem#drmSchemes}. */
|
|
||||||
public Builder setDrmSchemes(List<MediaItem.DrmScheme> drmSchemes) {
|
|
||||||
this.drmSchemes = Collections.unmodifiableList(new ArrayList<>(drmSchemes));
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** See {@link MediaItem#mimeType}. */
|
/** See {@link MediaItem#mimeType}. */
|
||||||
public Builder setMimeType(String mimeType) {
|
public Builder setMimeType(String mimeType) {
|
||||||
this.mimeType = mimeType;
|
this.mimeType = mimeType;
|
||||||
return this;
|
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. */
|
/** Returns a new {@link MediaItem} instance with the current builder values. */
|
||||||
public MediaItem build() {
|
public MediaItem build() {
|
||||||
return new MediaItem(
|
Assertions.checkNotNull(uri);
|
||||||
title,
|
return new MediaItem(uri, title, mimeType, drmConfiguration);
|
||||||
media,
|
|
||||||
drmSchemes,
|
|
||||||
mimeType);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Bundles a resource's URI with headers to attach to any request to that URI. */
|
/** DRM configuration for a media item. */
|
||||||
public static final class UriBundle {
|
public static final class DrmConfiguration {
|
||||||
|
|
||||||
/** An empty {@link UriBundle}. */
|
|
||||||
public static final UriBundle EMPTY = new UriBundle(Uri.EMPTY);
|
|
||||||
|
|
||||||
/** A URI. */
|
|
||||||
public final Uri uri;
|
|
||||||
|
|
||||||
/** The headers to attach to any request for the given URI. */
|
|
||||||
public final Map<String, String> requestHeaders;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an instance with no request headers.
|
|
||||||
*
|
|
||||||
* @param uri See {@link #uri}.
|
|
||||||
*/
|
|
||||||
public UriBundle(Uri uri) {
|
|
||||||
this(uri, Collections.emptyMap());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an instance with the given URI and request headers.
|
|
||||||
*
|
|
||||||
* @param uri See {@link #uri}.
|
|
||||||
* @param requestHeaders See {@link #requestHeaders}.
|
|
||||||
*/
|
|
||||||
public UriBundle(Uri uri, Map<String, String> requestHeaders) {
|
|
||||||
this.uri = uri;
|
|
||||||
this.requestHeaders = Collections.unmodifiableMap(new HashMap<>(requestHeaders));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(@Nullable Object other) {
|
|
||||||
if (this == other) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (other == null || getClass() != other.getClass()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
UriBundle uriBundle = (UriBundle) other;
|
|
||||||
return uri.equals(uriBundle.uri) && requestHeaders.equals(uriBundle.requestHeaders);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
int result = uri.hashCode();
|
|
||||||
result = 31 * result + requestHeaders.hashCode();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a DRM protection scheme, and optionally provides information about how to acquire
|
|
||||||
* the license for the media.
|
|
||||||
*/
|
|
||||||
public static final class DrmScheme {
|
|
||||||
|
|
||||||
/** The UUID of the protection scheme. */
|
/** The UUID of the protection scheme. */
|
||||||
public final UUID uuid;
|
public final UUID uuid;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Optional {@link UriBundle} for the license server. If no license server is provided, the
|
* Optional license server {@link Uri}. If {@code null} then the license server must be
|
||||||
* server must be provided by the media.
|
* specified by the media.
|
||||||
*/
|
*/
|
||||||
@Nullable public final UriBundle licenseServer;
|
@Nullable public final Uri licenseUri;
|
||||||
|
|
||||||
|
/** Headers that should be attached to any license requests. */
|
||||||
|
public final Map<String, String> requestHeaders;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an instance.
|
* Creates an instance.
|
||||||
*
|
*
|
||||||
* @param uuid See {@link #uuid}.
|
* @param uuid See {@link #uuid}.
|
||||||
* @param licenseServer See {@link #licenseServer}.
|
* @param licenseUri See {@link #licenseUri}.
|
||||||
|
* @param requestHeaders See {@link #requestHeaders}.
|
||||||
*/
|
*/
|
||||||
public DrmScheme(UUID uuid, @Nullable UriBundle licenseServer) {
|
public DrmConfiguration(
|
||||||
|
UUID uuid, @Nullable Uri licenseUri, @Nullable Map<String, String> requestHeaders) {
|
||||||
this.uuid = uuid;
|
this.uuid = uuid;
|
||||||
this.licenseServer = licenseServer;
|
this.licenseUri = licenseUri;
|
||||||
|
this.requestHeaders =
|
||||||
|
requestHeaders == null
|
||||||
|
? Collections.emptyMap()
|
||||||
|
: Collections.unmodifiableMap(requestHeaders);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean equals(@Nullable Object other) {
|
public boolean equals(@Nullable Object obj) {
|
||||||
if (this == other) {
|
if (this == obj) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (other == null || getClass() != other.getClass()) {
|
if (obj == null || getClass() != obj.getClass()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
DrmScheme drmScheme = (DrmScheme) other;
|
DrmConfiguration other = (DrmConfiguration) obj;
|
||||||
return uuid.equals(drmScheme.uuid) && Util.areEqual(licenseServer, drmScheme.licenseServer);
|
return uuid.equals(other.uuid)
|
||||||
|
&& Util.areEqual(licenseUri, other.licenseUri)
|
||||||
|
&& requestHeaders.equals(other.requestHeaders);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
int result = uuid.hashCode();
|
int result = uuid.hashCode();
|
||||||
result = 31 * result + (licenseServer != null ? licenseServer.hashCode() : 0);
|
result = 31 * result + (licenseUri != null ? licenseUri.hashCode() : 0);
|
||||||
|
result = 31 * result + requestHeaders.hashCode();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The title of the item. The default value is an empty string. */
|
/** The media {@link Uri}. */
|
||||||
public final String title;
|
public final Uri uri;
|
||||||
|
|
||||||
/**
|
/** The title of the item, or {@code null} if unspecified. */
|
||||||
* A {@link UriBundle} to fetch the media content. The default value is {@link UriBundle#EMPTY}.
|
@Nullable public final String title;
|
||||||
*/
|
|
||||||
public final UriBundle media;
|
|
||||||
|
|
||||||
/**
|
/** The mime type for the media, or {@code null} if unspecified. */
|
||||||
* Immutable list of {@link DrmScheme} instances sorted in decreasing order of preference. The
|
@Nullable public final String mimeType;
|
||||||
* default value is an empty list.
|
|
||||||
*/
|
|
||||||
public final List<DrmScheme> drmSchemes;
|
|
||||||
|
|
||||||
/**
|
/** Optional {@link DrmConfiguration} for the media. */
|
||||||
* The mime type of this media item. The default value is an empty string.
|
@Nullable public final DrmConfiguration drmConfiguration;
|
||||||
*
|
|
||||||
* <p>The usage of this mime type is optional and player implementation specific.
|
|
||||||
*/
|
|
||||||
public final String mimeType;
|
|
||||||
|
|
||||||
// TODO: Add support for sideloaded tracks, artwork, icon, and subtitle.
|
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
|
@Override
|
||||||
public boolean equals(@Nullable Object other) {
|
public boolean equals(@Nullable Object obj) {
|
||||||
if (this == other) {
|
if (this == obj) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (other == null || getClass() != other.getClass()) {
|
if (obj == null || getClass() != obj.getClass()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
MediaItem mediaItem = (MediaItem) other;
|
MediaItem other = (MediaItem) obj;
|
||||||
return title.equals(mediaItem.title)
|
return uri.equals(other.uri)
|
||||||
&& media.equals(mediaItem.media)
|
&& Util.areEqual(title, other.title)
|
||||||
&& drmSchemes.equals(mediaItem.drmSchemes)
|
&& Util.areEqual(mimeType, other.mimeType)
|
||||||
&& mimeType.equals(mediaItem.mimeType);
|
&& Util.areEqual(drmConfiguration, other.drmConfiguration);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
int result = title.hashCode();
|
int result = uri.hashCode();
|
||||||
result = 31 * result + media.hashCode();
|
result = 31 * result + (title == null ? 0 : title.hashCode());
|
||||||
result = 31 * result + drmSchemes.hashCode();
|
result = 31 * result + (drmConfiguration == null ? 0 : drmConfiguration.hashCode());
|
||||||
result = 31 * result + mimeType.hashCode();
|
result = 31 * result + (mimeType == null ? 0 : mimeType.hashCode());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
private MediaItem(
|
|
||||||
String title,
|
|
||||||
UriBundle media,
|
|
||||||
List<DrmScheme> drmSchemes,
|
|
||||||
String mimeType) {
|
|
||||||
this.title = title;
|
|
||||||
this.media = media;
|
|
||||||
this.drmSchemes = drmSchemes;
|
|
||||||
this.mimeType = mimeType;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -21,9 +21,7 @@ import android.net.Uri;
|
|||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
import com.google.android.exoplayer2.C;
|
import com.google.android.exoplayer2.C;
|
||||||
import com.google.android.exoplayer2.util.MimeTypes;
|
import com.google.android.exoplayer2.util.MimeTypes;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
@ -36,7 +34,7 @@ public class MediaItemTest {
|
|||||||
MediaItem.Builder builder = new MediaItem.Builder();
|
MediaItem.Builder builder = new MediaItem.Builder();
|
||||||
MediaItem item1 =
|
MediaItem item1 =
|
||||||
builder
|
builder
|
||||||
.setMedia("http://example.com")
|
.setUri(Uri.parse("http://example.com"))
|
||||||
.setTitle("title")
|
.setTitle("title")
|
||||||
.setMimeType(MimeTypes.AUDIO_MP4)
|
.setMimeType(MimeTypes.AUDIO_MP4)
|
||||||
.build();
|
.build();
|
||||||
@ -44,19 +42,20 @@ public class MediaItemTest {
|
|||||||
assertThat(item1).isEqualTo(item2);
|
assertThat(item1).isEqualTo(item2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void buildMediaItem_assertDefaultValues() {
|
|
||||||
assertDefaultValues(new MediaItem.Builder().build());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void equals_withEqualDrmSchemes_returnsTrue() {
|
public void equals_withEqualDrmSchemes_returnsTrue() {
|
||||||
MediaItem.Builder builder1 = new MediaItem.Builder();
|
MediaItem.Builder builder1 = new MediaItem.Builder();
|
||||||
MediaItem mediaItem1 =
|
MediaItem mediaItem1 =
|
||||||
builder1.setMedia("www.google.com").setDrmSchemes(createDummyDrmSchemes(1)).build();
|
builder1
|
||||||
|
.setUri(Uri.parse("www.google.com"))
|
||||||
|
.setDrmConfiguration(buildDrmConfiguration(1))
|
||||||
|
.build();
|
||||||
MediaItem.Builder builder2 = new MediaItem.Builder();
|
MediaItem.Builder builder2 = new MediaItem.Builder();
|
||||||
MediaItem mediaItem2 =
|
MediaItem mediaItem2 =
|
||||||
builder2.setMedia("www.google.com").setDrmSchemes(createDummyDrmSchemes(1)).build();
|
builder2
|
||||||
|
.setUri(Uri.parse("www.google.com"))
|
||||||
|
.setDrmConfiguration(buildDrmConfiguration(1))
|
||||||
|
.build();
|
||||||
assertThat(mediaItem1).isEqualTo(mediaItem2);
|
assertThat(mediaItem1).isEqualTo(mediaItem2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,33 +63,24 @@ public class MediaItemTest {
|
|||||||
public void equals_withDifferentDrmRequestHeaders_returnsFalse() {
|
public void equals_withDifferentDrmRequestHeaders_returnsFalse() {
|
||||||
MediaItem.Builder builder1 = new MediaItem.Builder();
|
MediaItem.Builder builder1 = new MediaItem.Builder();
|
||||||
MediaItem mediaItem1 =
|
MediaItem mediaItem1 =
|
||||||
builder1.setMedia("www.google.com").setDrmSchemes(createDummyDrmSchemes(1)).build();
|
builder1
|
||||||
|
.setUri(Uri.parse("www.google.com"))
|
||||||
|
.setDrmConfiguration(buildDrmConfiguration(1))
|
||||||
|
.build();
|
||||||
MediaItem.Builder builder2 = new MediaItem.Builder();
|
MediaItem.Builder builder2 = new MediaItem.Builder();
|
||||||
MediaItem mediaItem2 =
|
MediaItem mediaItem2 =
|
||||||
builder2.setMedia("www.google.com").setDrmSchemes(createDummyDrmSchemes(2)).build();
|
builder2
|
||||||
|
.setUri(Uri.parse("www.google.com"))
|
||||||
|
.setDrmConfiguration(buildDrmConfiguration(2))
|
||||||
|
.build();
|
||||||
assertThat(mediaItem1).isNotEqualTo(mediaItem2);
|
assertThat(mediaItem1).isNotEqualTo(mediaItem2);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void assertDefaultValues(MediaItem item) {
|
private static MediaItem.DrmConfiguration buildDrmConfiguration(int seed) {
|
||||||
assertThat(item.title).isEmpty();
|
HashMap<String, String> requestHeaders = new HashMap<>();
|
||||||
assertThat(item.media.uri).isEqualTo(Uri.EMPTY);
|
requestHeaders.put("key1", "value1");
|
||||||
assertThat(item.drmSchemes).isEmpty();
|
requestHeaders.put("key2", "value2" + seed);
|
||||||
assertThat(item.mimeType).isEmpty();
|
return new MediaItem.DrmConfiguration(
|
||||||
}
|
C.WIDEVINE_UUID, Uri.parse("www.uri1.com"), requestHeaders);
|
||||||
|
|
||||||
private static List<MediaItem.DrmScheme> createDummyDrmSchemes(int seed) {
|
|
||||||
HashMap<String, String> requestHeaders1 = new HashMap<>();
|
|
||||||
requestHeaders1.put("key1", "value1");
|
|
||||||
requestHeaders1.put("key2", "value1");
|
|
||||||
MediaItem.UriBundle uriBundle1 =
|
|
||||||
new MediaItem.UriBundle(Uri.parse("www.uri1.com"), requestHeaders1);
|
|
||||||
MediaItem.DrmScheme drmScheme1 = new MediaItem.DrmScheme(C.WIDEVINE_UUID, uriBundle1);
|
|
||||||
HashMap<String, String> requestHeaders2 = new HashMap<>();
|
|
||||||
requestHeaders2.put("key3", "value3");
|
|
||||||
requestHeaders2.put("key4", "valueWithSeed" + seed);
|
|
||||||
MediaItem.UriBundle uriBundle2 =
|
|
||||||
new MediaItem.UriBundle(Uri.parse("www.uri2.com"), requestHeaders2);
|
|
||||||
MediaItem.DrmScheme drmScheme2 = new MediaItem.DrmScheme(C.PLAYREADY_UUID, uriBundle2);
|
|
||||||
return Arrays.asList(drmScheme1, drmScheme2);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user