Skip to content

Commit

Permalink
Make MediaItems updateable
Browse files Browse the repository at this point in the history
This changes all MediaSources in our library to allow updates to
their MediaItems (if supported).

Issue: #9978
Issue: androidx/media#33
PiperOrigin-RevId: 546808812
  • Loading branch information
tonihei authored and rohitjoins committed Jul 13, 2023
1 parent db1efe6 commit ba16019
Show file tree
Hide file tree
Showing 20 changed files with 1,230 additions and 82 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
import android.os.Looper;
import android.util.Pair;
import android.view.ViewGroup;
import androidx.annotation.GuardedBy;
import androidx.annotation.MainThread;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
Expand Down Expand Up @@ -505,7 +506,6 @@ private MediaSourceResourceHolder(

private static final String TAG = "ImaSSAIMediaSource";

private final MediaItem mediaItem;
private final Player player;
private final MediaSource.Factory contentMediaSourceFactory;
private final AdsLoader adsLoader;
Expand All @@ -527,6 +527,9 @@ private MediaSourceResourceHolder(
@Nullable private Timeline contentTimeline;
private AdPlaybackState adPlaybackState;

@GuardedBy("this")
private MediaItem mediaItem;

private ImaServerSideAdInsertionMediaSource(
Player player,
MediaItem mediaItem,
Expand Down Expand Up @@ -565,10 +568,29 @@ private ImaServerSideAdInsertionMediaSource(
}

@Override
public MediaItem getMediaItem() {
public synchronized MediaItem getMediaItem() {
return mediaItem;
}

@Override
public boolean canUpdateMediaItem(MediaItem mediaItem) {
MediaItem existingMediaItem = getMediaItem();
MediaItem.LocalConfiguration existingConfiguration =
checkNotNull(existingMediaItem.localConfiguration);
@Nullable MediaItem.LocalConfiguration newConfiguration = mediaItem.localConfiguration;
return newConfiguration != null
&& newConfiguration.uri.equals(existingConfiguration.uri)
&& newConfiguration.streamKeys.equals(existingConfiguration.streamKeys)
&& Util.areEqual(newConfiguration.customCacheKey, existingConfiguration.customCacheKey)
&& Util.areEqual(newConfiguration.drmConfiguration, existingConfiguration.drmConfiguration)
&& existingMediaItem.liveConfiguration.equals(mediaItem.liveConfiguration);
}

@Override
public synchronized void updateMediaItem(MediaItem mediaItem) {
this.mediaItem = mediaItem;
}

@Override
public void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) {
mainHandler.post(() -> assertSingleInstanceInPlaylist(checkNotNull(player)));
Expand All @@ -594,6 +616,7 @@ public void prepareSourceInternal(@Nullable TransferListener mediaTransferListen
@Override
protected void onChildSourceInfoRefreshed(
Void childSourceId, MediaSource mediaSource, Timeline newTimeline) {
MediaItem mediaItem = getMediaItem();
refreshSourceInfo(
new ForwardingTimeline(newTimeline) {
@Override
Expand Down Expand Up @@ -734,6 +757,7 @@ private void invalidateServerSideAdInsertionAdPlaybackState() {

private void setContentUri(Uri contentUri) {
if (serverSideAdInsertionMediaSource == null) {
MediaItem mediaItem = getMediaItem();
MediaItem contentMediaItem =
new MediaItem.Builder()
.setUri(contentUri)
Expand Down Expand Up @@ -841,6 +865,7 @@ public void onPositionDiscontinuity(
return;
}

MediaItem mediaItem = getMediaItem();
if (mediaItem.equals(oldPosition.mediaItem) && !mediaItem.equals(newPosition.mediaItem)) {
// Playback automatically transitioned to the next media item. Notify the SDK.
streamPlayer.onContentCompleted();
Expand Down Expand Up @@ -912,7 +937,7 @@ public void onPositionDiscontinuity(

@Override
public void onMetadata(Metadata metadata) {
if (!isCurrentAdPlaying(player, mediaItem, adsId)) {
if (!isCurrentAdPlaying(player, getMediaItem(), adsId)) {
return;
}
for (int i = 0; i < metadata.length(); i++) {
Expand All @@ -932,14 +957,14 @@ public void onMetadata(Metadata metadata) {

@Override
public void onPlaybackStateChanged(@Player.State int state) {
if (state == Player.STATE_ENDED && isCurrentAdPlaying(player, mediaItem, adsId)) {
if (state == Player.STATE_ENDED && isCurrentAdPlaying(player, getMediaItem(), adsId)) {
streamPlayer.onContentCompleted();
}
}

@Override
public void onVolumeChanged(float volume) {
if (!isCurrentAdPlaying(player, mediaItem, adsId)) {
if (!isCurrentAdPlaying(player, getMediaItem(), adsId)) {
return;
}
int volumePct = (int) Math.floor(volume * 100);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.upstream.Allocator;
import com.google.android.exoplayer2.util.Assertions;
Expand Down Expand Up @@ -198,6 +199,12 @@ public ClippingMediaSource(
window = new Timeline.Window();
}

@Override
public boolean canUpdateMediaItem(MediaItem mediaItem) {
return getMediaItem().clippingConfiguration.equals(mediaItem.clippingConfiguration)
&& mediaSource.canUpdateMediaItem(mediaItem);
}

@Override
public void maybeThrowSourceInfoRefreshError() throws IOException {
if (clippingError != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import android.os.Handler;
import android.os.Message;
import android.util.Pair;
import androidx.annotation.GuardedBy;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.MediaItem;
Expand Down Expand Up @@ -215,13 +216,15 @@ public ConcatenatingMediaSource2 build() {

private static final int MSG_UPDATE_TIMELINE = 0;

private final MediaItem mediaItem;
private final ImmutableList<MediaSourceHolder> mediaSourceHolders;
private final IdentityHashMap<MediaPeriod, MediaSourceHolder> mediaSourceByMediaPeriod;

@Nullable private Handler playbackThreadHandler;
private boolean timelineUpdateScheduled;

@GuardedBy("this")
private MediaItem mediaItem;

private ConcatenatingMediaSource2(
MediaItem mediaItem, ImmutableList<MediaSourceHolder> mediaSourceHolders) {
this.mediaItem = mediaItem;
Expand All @@ -236,10 +239,20 @@ public Timeline getInitialTimeline() {
}

@Override
public MediaItem getMediaItem() {
public synchronized MediaItem getMediaItem() {
return mediaItem;
}

@Override
public boolean canUpdateMediaItem(MediaItem mediaItem) {
return true;
}

@Override
public synchronized void updateMediaItem(MediaItem mediaItem) {
this.mediaItem = mediaItem;
}

@Override
protected void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) {
super.prepareSourceInternal(mediaTransferListener);
Expand Down Expand Up @@ -430,7 +443,7 @@ private ConcatenatedTimeline maybeCreateConcatenatedTimeline() {
}
}
return new ConcatenatedTimeline(
mediaItem,
getMediaItem(),
timelinesBuilder.build(),
firstPeriodIndicesBuilder.build(),
periodOffsetsInWindowUsBuilder.build(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import android.net.Uri;
import android.os.Looper;
import androidx.annotation.GuardedBy;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.MediaItem;
Expand All @@ -34,6 +35,7 @@
import com.google.android.exoplayer2.upstream.DefaultLoadErrorHandlingPolicy;
import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy;
import com.google.android.exoplayer2.upstream.TransferListener;
import com.google.android.exoplayer2.util.Util;
import com.google.errorprone.annotations.CanIgnoreReturnValue;

/**
Expand Down Expand Up @@ -230,8 +232,6 @@ public ProgressiveMediaSource createMediaSource(MediaItem mediaItem) {
*/
public static final int DEFAULT_LOADING_CHECK_INTERVAL_BYTES = 1024 * 1024;

private final MediaItem mediaItem;
private final MediaItem.LocalConfiguration localConfiguration;
private final DataSource.Factory dataSourceFactory;
private final ProgressiveMediaExtractor.Factory progressiveMediaExtractorFactory;
private final DrmSessionManager drmSessionManager;
Expand All @@ -244,14 +244,16 @@ public ProgressiveMediaSource createMediaSource(MediaItem mediaItem) {
private boolean timelineIsLive;
@Nullable private TransferListener transferListener;

@GuardedBy("this")
private MediaItem mediaItem;

private ProgressiveMediaSource(
MediaItem mediaItem,
DataSource.Factory dataSourceFactory,
ProgressiveMediaExtractor.Factory progressiveMediaExtractorFactory,
DrmSessionManager drmSessionManager,
LoadErrorHandlingPolicy loadableLoadErrorHandlingPolicy,
int continueLoadingCheckIntervalBytes) {
this.localConfiguration = checkNotNull(mediaItem.localConfiguration);
this.mediaItem = mediaItem;
this.dataSourceFactory = dataSourceFactory;
this.progressiveMediaExtractorFactory = progressiveMediaExtractorFactory;
Expand All @@ -263,10 +265,24 @@ private ProgressiveMediaSource(
}

@Override
public MediaItem getMediaItem() {
public synchronized MediaItem getMediaItem() {
return mediaItem;
}

@Override
public boolean canUpdateMediaItem(MediaItem mediaItem) {
MediaItem.LocalConfiguration existingConfiguration = getLocalConfiguration();
@Nullable MediaItem.LocalConfiguration newConfiguration = mediaItem.localConfiguration;
return newConfiguration != null
&& newConfiguration.uri.equals(existingConfiguration.uri)
&& Util.areEqual(newConfiguration.customCacheKey, existingConfiguration.customCacheKey);
}

@Override
public synchronized void updateMediaItem(MediaItem mediaItem) {
this.mediaItem = mediaItem;
}

@Override
protected void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) {
transferListener = mediaTransferListener;
Expand All @@ -287,6 +303,7 @@ public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator, long star
if (transferListener != null) {
dataSource.addTransferListener(transferListener);
}
MediaItem.LocalConfiguration localConfiguration = getLocalConfiguration();
return new ProgressiveMediaPeriod(
localConfiguration.uri,
dataSource,
Expand Down Expand Up @@ -333,6 +350,10 @@ public void onSourceInfoRefreshed(long durationUs, boolean isSeekable, boolean i

// Internal methods.

private MediaItem.LocalConfiguration getLocalConfiguration() {
return checkNotNull(getMediaItem().localConfiguration);
}

private void notifySourceInfoRefreshed() {
// TODO: Split up isDynamic into multiple fields to indicate which values may change. Then
// indicate that the duration may change until it's known. See [internal: b/69703223].
Expand All @@ -343,7 +364,7 @@ private void notifySourceInfoRefreshed() {
/* isDynamic= */ false,
/* useLiveConfiguration= */ timelineIsLive,
/* manifest= */ null,
mediaItem);
getMediaItem());
if (timelineIsPlaceholder) {
// TODO: Actually prepare the extractors during preparation so that we don't need a
// placeholder. See https://github.com/google/ExoPlayer/issues/4727.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import static java.lang.Math.min;

import android.net.Uri;
import androidx.annotation.GuardedBy;
import androidx.annotation.IntRange;
import androidx.annotation.Nullable;
import com.google.android.exoplayer2.C;
Expand Down Expand Up @@ -113,7 +114,9 @@ public SilenceMediaSource createMediaSource() {
new byte[Util.getPcmFrameSize(PCM_ENCODING, CHANNEL_COUNT) * 1024];

private final long durationUs;
private final MediaItem mediaItem;

@GuardedBy("this")
private MediaItem mediaItem;

/**
* Creates a new media source providing silent audio of the given duration.
Expand Down Expand Up @@ -145,7 +148,7 @@ protected void prepareSourceInternal(@Nullable TransferListener mediaTransferLis
/* isDynamic= */ false,
/* useLiveConfiguration= */ false,
/* manifest= */ null,
mediaItem));
getMediaItem()));
}

@Override
Expand All @@ -160,10 +163,20 @@ public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator, long star
public void releasePeriod(MediaPeriod mediaPeriod) {}

@Override
public MediaItem getMediaItem() {
public synchronized MediaItem getMediaItem() {
return mediaItem;
}

@Override
public boolean canUpdateMediaItem(MediaItem mediaItem) {
return true;
}

@Override
public synchronized void updateMediaItem(MediaItem mediaItem) {
this.mediaItem = mediaItem;
}

@Override
protected void releaseSourceInternal() {}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,8 @@ public MediaItem getMediaItem() {

@Override
public boolean canUpdateMediaItem(MediaItem mediaItem) {
return contentMediaSource.canUpdateMediaItem(mediaItem);
return Util.areEqual(getAdsConfiguration(getMediaItem()), getAdsConfiguration(mediaItem))
&& contentMediaSource.canUpdateMediaItem(mediaItem);
}

@Override
Expand Down Expand Up @@ -373,6 +374,13 @@ private long[][] getAdDurationsUs() {
return adDurationsUs;
}

@Nullable
private static MediaItem.AdsConfiguration getAdsConfiguration(MediaItem mediaItem) {
return mediaItem.localConfiguration == null
? null
: mediaItem.localConfiguration.adsConfiguration;
}

/** Listener for component events. All methods are called on the main thread. */
private final class ComponentListener implements AdsLoader.EventListener {

Expand Down
Loading

0 comments on commit ba16019

Please sign in to comment.