Move DrmSessionManager initial player setup to its own method.

Currently, DrmSessionManager takes player specific values (= the
playback looper) through (pre)acquireSession calls and requires
the caller to pass in the same values every time.

Instead, we can configure the DrmSessionManager for playback with
a player once before it's being used. We can't simply extend the
prepare() method as prepare may be called before the player is
created to prewarm the DrmSessionManager.

The new method also takes a PlayerId which is bound to the lifetime
of the player similar to the playback looper.

To avoid breakage of custom MediaSources with DRM, we can keep the
old the SampleQueue.createWithDrm method as deprecated.

PiperOrigin-RevId: 410998240
This commit is contained in:
tonihei 2021-11-19 09:14:29 +00:00 committed by Ian Baker
parent 00a13a5159
commit 9af85d9b25
15 changed files with 147 additions and 208 deletions

View File

@ -18,6 +18,7 @@ package androidx.media3.exoplayer.drm;
import static androidx.media3.common.util.Assertions.checkArgument; import static androidx.media3.common.util.Assertions.checkArgument;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Assertions.checkState; import static androidx.media3.common.util.Assertions.checkState;
import static androidx.media3.common.util.Assertions.checkStateNotNull;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.media.ResourceBusyException; import android.media.ResourceBusyException;
@ -37,6 +38,7 @@ import androidx.media3.common.PlaybackException;
import androidx.media3.common.util.Log; import androidx.media3.common.util.Log;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.common.util.Util; import androidx.media3.common.util.Util;
import androidx.media3.exoplayer.analytics.PlayerId;
import androidx.media3.exoplayer.drm.DrmSession.DrmSessionException; import androidx.media3.exoplayer.drm.DrmSession.DrmSessionException;
import androidx.media3.exoplayer.drm.ExoMediaDrm.OnEventListener; import androidx.media3.exoplayer.drm.ExoMediaDrm.OnEventListener;
import androidx.media3.exoplayer.upstream.DefaultLoadErrorHandlingPolicy; import androidx.media3.exoplayer.upstream.DefaultLoadErrorHandlingPolicy;
@ -61,7 +63,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
* A {@link DrmSessionManager} that supports playbacks using {@link ExoMediaDrm}. * A {@link DrmSessionManager} that supports playbacks using {@link ExoMediaDrm}.
* *
* <p>This implementation supports pre-acquisition of sessions using {@link * <p>This implementation supports pre-acquisition of sessions using {@link
* #preacquireSession(Looper, DrmSessionEventListener.EventDispatcher, Format)}. * #preacquireSession(DrmSessionEventListener.EventDispatcher, Format)}.
*/ */
@RequiresApi(18) @RequiresApi(18)
@UnstableApi @UnstableApi
@ -422,8 +424,8 @@ public class DefaultDrmSessionManager implements DrmSessionManager {
/** /**
* Sets the mode, which determines the role of sessions acquired from the instance. This must be * Sets the mode, which determines the role of sessions acquired from the instance. This must be
* called before {@link #acquireSession(Looper, DrmSessionEventListener.EventDispatcher, Format)} * called before {@link #acquireSession(DrmSessionEventListener.EventDispatcher, Format)} is
* is called. * called.
* *
* <p>By default, the mode is {@link #MODE_PLAYBACK} and a streaming license is requested when * <p>By default, the mode is {@link #MODE_PLAYBACK} and a streaming license is requested when
* required. * required.
@ -491,12 +493,15 @@ public class DefaultDrmSessionManager implements DrmSessionManager {
} }
@Override @Override
public DrmSessionReference preacquireSession( public void setPlayer(Looper playbackLooper, PlayerId playerId) {
Looper playbackLooper,
@Nullable DrmSessionEventListener.EventDispatcher eventDispatcher,
Format format) {
checkState(prepareCallsCount > 0);
initPlaybackLooper(playbackLooper); initPlaybackLooper(playbackLooper);
}
@Override
public DrmSessionReference preacquireSession(
@Nullable DrmSessionEventListener.EventDispatcher eventDispatcher, Format format) {
checkState(prepareCallsCount > 0);
checkStateNotNull(playbackLooper);
PreacquiredSessionReference preacquiredSessionReference = PreacquiredSessionReference preacquiredSessionReference =
new PreacquiredSessionReference(eventDispatcher); new PreacquiredSessionReference(eventDispatcher);
preacquiredSessionReference.acquire(format); preacquiredSessionReference.acquire(format);
@ -506,11 +511,9 @@ public class DefaultDrmSessionManager implements DrmSessionManager {
@Override @Override
@Nullable @Nullable
public DrmSession acquireSession( public DrmSession acquireSession(
Looper playbackLooper, @Nullable DrmSessionEventListener.EventDispatcher eventDispatcher, Format format) {
@Nullable DrmSessionEventListener.EventDispatcher eventDispatcher,
Format format) {
checkState(prepareCallsCount > 0); checkState(prepareCallsCount > 0);
initPlaybackLooper(playbackLooper); checkStateNotNull(playbackLooper);
return acquireSession( return acquireSession(
playbackLooper, playbackLooper,
eventDispatcher, eventDispatcher,
@ -980,7 +983,7 @@ public class DefaultDrmSessionManager implements DrmSessionManager {
* Constructs an instance. * Constructs an instance.
* *
* @param eventDispatcher The {@link DrmSessionEventListener.EventDispatcher} passed to {@link * @param eventDispatcher The {@link DrmSessionEventListener.EventDispatcher} passed to {@link
* #acquireSession(Looper, DrmSessionEventListener.EventDispatcher, Format)}. * #acquireSession(DrmSessionEventListener.EventDispatcher, Format)}.
*/ */
public PreacquiredSessionReference( public PreacquiredSessionReference(
@Nullable DrmSessionEventListener.EventDispatcher eventDispatcher) { @Nullable DrmSessionEventListener.EventDispatcher eventDispatcher) {

View File

@ -21,6 +21,7 @@ import androidx.media3.common.C;
import androidx.media3.common.Format; import androidx.media3.common.Format;
import androidx.media3.common.PlaybackException; import androidx.media3.common.PlaybackException;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.exoplayer.analytics.PlayerId;
/** Manages a DRM session. */ /** Manages a DRM session. */
@UnstableApi @UnstableApi
@ -47,12 +48,13 @@ public interface DrmSessionManager {
DrmSessionManager DRM_UNSUPPORTED = DrmSessionManager DRM_UNSUPPORTED =
new DrmSessionManager() { new DrmSessionManager() {
@Override
public void setPlayer(Looper playbackLooper, PlayerId playerId) {}
@Override @Override
@Nullable @Nullable
public DrmSession acquireSession( public DrmSession acquireSession(
Looper playbackLooper, @Nullable DrmSessionEventListener.EventDispatcher eventDispatcher, Format format) {
@Nullable DrmSessionEventListener.EventDispatcher eventDispatcher,
Format format) {
if (format.drmInitData == null) { if (format.drmInitData == null) {
return null; return null;
} else { } else {
@ -102,25 +104,33 @@ public interface DrmSessionManager {
// Do nothing. // Do nothing.
} }
/**
* Sets information about the player using this DRM session manager.
*
* @param playbackLooper The {@link Looper} associated with the player's playback thread.
* @param playerId The {@link PlayerId} of the player.
*/
void setPlayer(Looper playbackLooper, PlayerId playerId);
/** /**
* Pre-acquires a DRM session for the specified {@link Format}. * Pre-acquires a DRM session for the specified {@link Format}.
* *
* <p>This notifies the manager that a subsequent call to {@link #acquireSession(Looper, * <p>This notifies the manager that a subsequent call to {@link #acquireSession(
* DrmSessionEventListener.EventDispatcher, Format)} with the same {@link Format} is likely, * DrmSessionEventListener.EventDispatcher, Format)} with the same {@link Format} is likely,
* allowing a manager that supports pre-acquisition to get the required {@link DrmSession} ready * allowing a manager that supports pre-acquisition to get the required {@link DrmSession} ready
* in the background. * in the background.
* *
* <p>The caller must call {@link DrmSessionReference#release()} on the returned instance when * <p>The caller must call {@link DrmSessionReference#release()} on the returned instance when
* they no longer require the pre-acquisition (i.e. they know they won't be making a matching call * they no longer require the pre-acquisition (i.e. they know they won't be making a matching call
* to {@link #acquireSession(Looper, DrmSessionEventListener.EventDispatcher, Format)} in the near * to {@link #acquireSession(DrmSessionEventListener.EventDispatcher, Format)} in the near
* future). * future).
* *
* <p>This manager may silently release the underlying session in order to allow another operation * <p>This manager may silently release the underlying session in order to allow another operation
* to complete. This will result in a subsequent call to {@link #acquireSession(Looper, * to complete. This will result in a subsequent call to {@link #acquireSession(
* DrmSessionEventListener.EventDispatcher, Format)} re-initializing a new session, including * DrmSessionEventListener.EventDispatcher, Format)} re-initializing a new session, including
* repeating key loads and other async initialization steps. * repeating key loads and other async initialization steps.
* *
* <p>The caller must separately call {@link #acquireSession(Looper, * <p>The caller must separately call {@link #acquireSession(
* DrmSessionEventListener.EventDispatcher, Format)} in order to obtain a session suitable for * DrmSessionEventListener.EventDispatcher, Format)} in order to obtain a session suitable for
* playback. The pre-acquired {@link DrmSessionReference} and full {@link DrmSession} instances * playback. The pre-acquired {@link DrmSessionReference} and full {@link DrmSession} instances
* are distinct. The caller must release both, and can release the {@link DrmSessionReference} * are distinct. The caller must release both, and can release the {@link DrmSessionReference}
@ -131,19 +141,15 @@ public interface DrmSessionManager {
* <p>Implementations that do not support pre-acquisition always return an empty {@link * <p>Implementations that do not support pre-acquisition always return an empty {@link
* DrmSessionReference} instance. * DrmSessionReference} instance.
* *
* @param playbackLooper The looper associated with the media playback thread.
* @param eventDispatcher The {@link DrmSessionEventListener.EventDispatcher} used to distribute * @param eventDispatcher The {@link DrmSessionEventListener.EventDispatcher} used to distribute
* events, and passed on to {@link * events, and passed on to {@link
* DrmSession#acquire(DrmSessionEventListener.EventDispatcher)}. * DrmSession#acquire(DrmSessionEventListener.EventDispatcher)}.
* @param format The {@link Format} for which to pre-acquire a {@link DrmSession}. * @param format The {@link Format} for which to pre-acquire a {@link DrmSession}.
* @return A releaser for the pre-acquired session. Guaranteed to be non-null even if the matching * @return A releaser for the pre-acquired session. Guaranteed to be non-null even if the matching
* {@link #acquireSession(Looper, DrmSessionEventListener.EventDispatcher, Format)} would * {@link #acquireSession(DrmSessionEventListener.EventDispatcher, Format)} would return null.
* return null.
*/ */
default DrmSessionReference preacquireSession( default DrmSessionReference preacquireSession(
Looper playbackLooper, @Nullable DrmSessionEventListener.EventDispatcher eventDispatcher, Format format) {
@Nullable DrmSessionEventListener.EventDispatcher eventDispatcher,
Format format) {
return DrmSessionReference.EMPTY; return DrmSessionReference.EMPTY;
} }
@ -160,7 +166,6 @@ public interface DrmSessionManager {
* used to configure secure decoders for playback of clear content periods, which can reduce the * used to configure secure decoders for playback of clear content periods, which can reduce the
* cost of transitioning between clear and encrypted content. * cost of transitioning between clear and encrypted content.
* *
* @param playbackLooper The looper associated with the media playback thread.
* @param eventDispatcher The {@link DrmSessionEventListener.EventDispatcher} used to distribute * @param eventDispatcher The {@link DrmSessionEventListener.EventDispatcher} used to distribute
* events, and passed on to {@link * events, and passed on to {@link
* DrmSession#acquire(DrmSessionEventListener.EventDispatcher)}. * DrmSession#acquire(DrmSessionEventListener.EventDispatcher)}.
@ -169,9 +174,7 @@ public interface DrmSessionManager {
*/ */
@Nullable @Nullable
DrmSession acquireSession( DrmSession acquireSession(
Looper playbackLooper, @Nullable DrmSessionEventListener.EventDispatcher eventDispatcher, Format format);
@Nullable DrmSessionEventListener.EventDispatcher eventDispatcher,
Format format);
/** /**
* Returns the {@link C.CryptoType} that the DRM session manager will use for a given {@link * Returns the {@link C.CryptoType} that the DRM session manager will use for a given {@link

View File

@ -27,6 +27,7 @@ import androidx.media3.common.Format;
import androidx.media3.common.util.Assertions; import androidx.media3.common.util.Assertions;
import androidx.media3.common.util.UnstableApi; import androidx.media3.common.util.UnstableApi;
import androidx.media3.datasource.HttpDataSource; import androidx.media3.datasource.HttpDataSource;
import androidx.media3.exoplayer.analytics.PlayerId;
import androidx.media3.exoplayer.drm.DefaultDrmSessionManager.Mode; import androidx.media3.exoplayer.drm.DefaultDrmSessionManager.Mode;
import androidx.media3.exoplayer.drm.DrmSession.DrmSessionException; import androidx.media3.exoplayer.drm.DrmSession.DrmSessionException;
import androidx.media3.exoplayer.source.MediaSource.MediaPeriodId; import androidx.media3.exoplayer.source.MediaSource.MediaPeriodId;
@ -238,6 +239,7 @@ public final class OfflineLicenseHelper {
public synchronized Pair<Long, Long> getLicenseDurationRemainingSec(byte[] offlineLicenseKeySetId) public synchronized Pair<Long, Long> getLicenseDurationRemainingSec(byte[] offlineLicenseKeySetId)
throws DrmSessionException { throws DrmSessionException {
Assertions.checkNotNull(offlineLicenseKeySetId); Assertions.checkNotNull(offlineLicenseKeySetId);
drmSessionManager.setPlayer(handlerThread.getLooper(), PlayerId.UNSET);
drmSessionManager.prepare(); drmSessionManager.prepare();
DrmSession drmSession = DrmSession drmSession =
openBlockingKeyRequest( openBlockingKeyRequest(
@ -266,6 +268,7 @@ public final class OfflineLicenseHelper {
private byte[] blockingKeyRequest( private byte[] blockingKeyRequest(
@Mode int licenseMode, @Nullable byte[] offlineLicenseKeySetId, Format format) @Mode int licenseMode, @Nullable byte[] offlineLicenseKeySetId, Format format)
throws DrmSessionException { throws DrmSessionException {
drmSessionManager.setPlayer(handlerThread.getLooper(), PlayerId.UNSET);
drmSessionManager.prepare(); drmSessionManager.prepare();
DrmSession drmSession = openBlockingKeyRequest(licenseMode, offlineLicenseKeySetId, format); DrmSession drmSession = openBlockingKeyRequest(licenseMode, offlineLicenseKeySetId, format);
DrmSessionException error = drmSession.getError(); DrmSessionException error = drmSession.getError();
@ -283,8 +286,7 @@ public final class OfflineLicenseHelper {
Assertions.checkNotNull(format.drmInitData); Assertions.checkNotNull(format.drmInitData);
drmSessionManager.setMode(licenseMode, offlineLicenseKeySetId); drmSessionManager.setMode(licenseMode, offlineLicenseKeySetId);
conditionVariable.close(); conditionVariable.close();
DrmSession drmSession = DrmSession drmSession = drmSessionManager.acquireSession(eventDispatcher, format);
drmSessionManager.acquireSession(handlerThread.getLooper(), eventDispatcher, format);
// Block current thread until key loading is finished // Block current thread until key loading is finished
conditionVariable.block(); conditionVariable.block();
return Assertions.checkNotNull(drmSession); return Assertions.checkNotNull(drmSession);

View File

@ -719,11 +719,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
} }
} }
SampleQueue trackOutput = SampleQueue trackOutput =
SampleQueue.createWithDrm( SampleQueue.createWithDrm(allocator, drmSessionManager, drmEventDispatcher);
allocator,
/* playbackLooper= */ handler.getLooper(),
drmSessionManager,
drmEventDispatcher);
trackOutput.setUpstreamFormatChangeListener(this); trackOutput.setUpstreamFormatChangeListener(this);
@NullableType @NullableType
TrackId[] sampleQueueTrackIds = Arrays.copyOf(this.sampleQueueTrackIds, trackCount + 1); TrackId[] sampleQueueTrackIds = Arrays.copyOf(this.sampleQueueTrackIds, trackCount + 1);

View File

@ -18,6 +18,7 @@ package androidx.media3.exoplayer.source;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import android.net.Uri; import android.net.Uri;
import android.os.Looper;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.media3.common.C; import androidx.media3.common.C;
import androidx.media3.common.MediaItem; import androidx.media3.common.MediaItem;
@ -298,6 +299,8 @@ public final class ProgressiveMediaSource extends BaseMediaSource
protected void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) { protected void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) {
transferListener = mediaTransferListener; transferListener = mediaTransferListener;
drmSessionManager.prepare(); drmSessionManager.prepare();
drmSessionManager.setPlayer(
/* playbackLooper= */ checkNotNull(Looper.myLooper()), getPlayerId());
notifySourceInfoRefreshed(); notifySourceInfoRefreshed();
} }

View File

@ -40,8 +40,10 @@ import androidx.media3.common.util.Util;
import androidx.media3.decoder.DecoderInputBuffer; import androidx.media3.decoder.DecoderInputBuffer;
import androidx.media3.decoder.DecoderInputBuffer.InsufficientCapacityException; import androidx.media3.decoder.DecoderInputBuffer.InsufficientCapacityException;
import androidx.media3.exoplayer.FormatHolder; import androidx.media3.exoplayer.FormatHolder;
import androidx.media3.exoplayer.analytics.PlayerId;
import androidx.media3.exoplayer.drm.DrmSession; import androidx.media3.exoplayer.drm.DrmSession;
import androidx.media3.exoplayer.drm.DrmSessionEventListener; import androidx.media3.exoplayer.drm.DrmSessionEventListener;
import androidx.media3.exoplayer.drm.DrmSessionEventListener.EventDispatcher;
import androidx.media3.exoplayer.drm.DrmSessionManager; import androidx.media3.exoplayer.drm.DrmSessionManager;
import androidx.media3.exoplayer.drm.DrmSessionManager.DrmSessionReference; import androidx.media3.exoplayer.drm.DrmSessionManager.DrmSessionReference;
import androidx.media3.exoplayer.source.SampleStream.ReadFlags; import androidx.media3.exoplayer.source.SampleStream.ReadFlags;
@ -73,7 +75,6 @@ public class SampleQueue implements TrackOutput {
private final SpannedData<SharedSampleMetadata> sharedSampleMetadata; private final SpannedData<SharedSampleMetadata> sharedSampleMetadata;
@Nullable private final DrmSessionManager drmSessionManager; @Nullable private final DrmSessionManager drmSessionManager;
@Nullable private final DrmSessionEventListener.EventDispatcher drmEventDispatcher; @Nullable private final DrmSessionEventListener.EventDispatcher drmEventDispatcher;
@Nullable private final Looper playbackLooper;
@Nullable private UpstreamFormatChangedListener upstreamFormatChangeListener; @Nullable private UpstreamFormatChangedListener upstreamFormatChangeListener;
@Nullable private Format downstreamFormat; @Nullable private Format downstreamFormat;
@ -115,10 +116,7 @@ public class SampleQueue implements TrackOutput {
*/ */
public static SampleQueue createWithoutDrm(Allocator allocator) { public static SampleQueue createWithoutDrm(Allocator allocator) {
return new SampleQueue( return new SampleQueue(
allocator, allocator, /* drmSessionManager= */ null, /* drmEventDispatcher= */ null);
/* playbackLooper= */ null,
/* drmSessionManager= */ null,
/* drmEventDispatcher= */ null);
} }
/** /**
@ -128,7 +126,6 @@ public class SampleQueue implements TrackOutput {
* keys needed to decrypt it. * keys needed to decrypt it.
* *
* @param allocator An {@link Allocator} from which allocations for sample data can be obtained. * @param allocator An {@link Allocator} from which allocations for sample data can be obtained.
* @param playbackLooper The looper associated with the media playback thread.
* @param drmSessionManager The {@link DrmSessionManager} to obtain {@link DrmSession DrmSessions} * @param drmSessionManager The {@link DrmSessionManager} to obtain {@link DrmSession DrmSessions}
* from. The created instance does not take ownership of this {@link DrmSessionManager}. * from. The created instance does not take ownership of this {@link DrmSessionManager}.
* @param drmEventDispatcher A {@link DrmSessionEventListener.EventDispatcher} to notify of events * @param drmEventDispatcher A {@link DrmSessionEventListener.EventDispatcher} to notify of events
@ -136,22 +133,36 @@ public class SampleQueue implements TrackOutput {
*/ */
public static SampleQueue createWithDrm( public static SampleQueue createWithDrm(
Allocator allocator, Allocator allocator,
Looper playbackLooper,
DrmSessionManager drmSessionManager, DrmSessionManager drmSessionManager,
DrmSessionEventListener.EventDispatcher drmEventDispatcher) { DrmSessionEventListener.EventDispatcher drmEventDispatcher) {
return new SampleQueue( return new SampleQueue(
allocator, allocator,
Assertions.checkNotNull(playbackLooper), Assertions.checkNotNull(drmSessionManager),
Assertions.checkNotNull(drmEventDispatcher));
}
/**
* @deprecated Use {@link #createWithDrm(Allocator, DrmSessionManager, EventDispatcher)} instead.
* The {@code playbackLooper} should be configured on the {@link DrmSessionManager} with
* {@link DrmSessionManager#setPlayer(Looper, PlayerId)}.
*/
@Deprecated
public static SampleQueue createWithDrm(
Allocator allocator,
Looper playbackLooper,
DrmSessionManager drmSessionManager,
DrmSessionEventListener.EventDispatcher drmEventDispatcher) {
drmSessionManager.setPlayer(playbackLooper, PlayerId.UNSET);
return new SampleQueue(
allocator,
Assertions.checkNotNull(drmSessionManager), Assertions.checkNotNull(drmSessionManager),
Assertions.checkNotNull(drmEventDispatcher)); Assertions.checkNotNull(drmEventDispatcher));
} }
protected SampleQueue( protected SampleQueue(
Allocator allocator, Allocator allocator,
@Nullable Looper playbackLooper,
@Nullable DrmSessionManager drmSessionManager, @Nullable DrmSessionManager drmSessionManager,
@Nullable DrmSessionEventListener.EventDispatcher drmEventDispatcher) { @Nullable DrmSessionEventListener.EventDispatcher drmEventDispatcher) {
this.playbackLooper = playbackLooper;
this.drmSessionManager = drmSessionManager; this.drmSessionManager = drmSessionManager;
this.drmEventDispatcher = drmEventDispatcher; this.drmEventDispatcher = drmEventDispatcher;
sampleDataQueue = new SampleDataQueue(allocator); sampleDataQueue = new SampleDataQueue(allocator);
@ -805,8 +816,7 @@ public class SampleQueue implements TrackOutput {
|| !sharedSampleMetadata.getEndValue().format.equals(upstreamFormat)) { || !sharedSampleMetadata.getEndValue().format.equals(upstreamFormat)) {
DrmSessionReference drmSessionReference = DrmSessionReference drmSessionReference =
drmSessionManager != null drmSessionManager != null
? drmSessionManager.preacquireSession( ? drmSessionManager.preacquireSession(drmEventDispatcher, upstreamFormat)
checkNotNull(playbackLooper), drmEventDispatcher, upstreamFormat)
: DrmSessionReference.EMPTY; : DrmSessionReference.EMPTY;
sharedSampleMetadata.appendSpan( sharedSampleMetadata.appendSpan(
@ -915,9 +925,7 @@ public class SampleQueue implements TrackOutput {
// Ensure we acquire the new session before releasing the previous one in case the same session // Ensure we acquire the new session before releasing the previous one in case the same session
// is being used for both DrmInitData. // is being used for both DrmInitData.
@Nullable DrmSession previousSession = currentDrmSession; @Nullable DrmSession previousSession = currentDrmSession;
currentDrmSession = currentDrmSession = drmSessionManager.acquireSession(drmEventDispatcher, newFormat);
drmSessionManager.acquireSession(
Assertions.checkNotNull(playbackLooper), drmEventDispatcher, newFormat);
outputFormatHolder.drmSession = currentDrmSession; outputFormatHolder.drmSession = currentDrmSession;
if (previousSession != null) { if (previousSession != null) {

View File

@ -19,7 +19,6 @@ import static androidx.media3.common.util.Assertions.checkNotNull;
import static java.lang.Math.max; import static java.lang.Math.max;
import static java.lang.Math.min; import static java.lang.Math.min;
import android.os.Looper;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.media3.common.C; import androidx.media3.common.C;
import androidx.media3.common.Format; import androidx.media3.common.Format;
@ -146,11 +145,7 @@ public class ChunkSampleStream<T extends ChunkSource>
SampleQueue[] sampleQueues = new SampleQueue[1 + embeddedTrackCount]; SampleQueue[] sampleQueues = new SampleQueue[1 + embeddedTrackCount];
primarySampleQueue = primarySampleQueue =
SampleQueue.createWithDrm( SampleQueue.createWithDrm(allocator, drmSessionManager, drmEventDispatcher);
allocator,
/* playbackLooper= */ checkNotNull(Looper.myLooper()),
drmSessionManager,
drmEventDispatcher);
trackTypes[0] = primaryTrackType; trackTypes[0] = primaryTrackType;
sampleQueues[0] = primarySampleQueue; sampleQueues[0] = primarySampleQueue;

View File

@ -27,6 +27,7 @@ import androidx.media3.common.DrmInitData;
import androidx.media3.common.Format; import androidx.media3.common.Format;
import androidx.media3.common.MimeTypes; import androidx.media3.common.MimeTypes;
import androidx.media3.common.util.Util; import androidx.media3.common.util.Util;
import androidx.media3.exoplayer.analytics.PlayerId;
import androidx.media3.exoplayer.drm.DrmSessionManager.DrmSessionReference; import androidx.media3.exoplayer.drm.DrmSessionManager.DrmSessionReference;
import androidx.media3.exoplayer.drm.ExoMediaDrm.AppManagedProvider; import androidx.media3.exoplayer.drm.ExoMediaDrm.AppManagedProvider;
import androidx.media3.exoplayer.source.MediaSource; import androidx.media3.exoplayer.source.MediaSource;
@ -68,12 +69,11 @@ public class DefaultDrmSessionManagerTest {
.setUuidAndExoMediaDrmProvider(DRM_SCHEME_UUID, uuid -> new FakeExoMediaDrm()) .setUuidAndExoMediaDrmProvider(DRM_SCHEME_UUID, uuid -> new FakeExoMediaDrm())
.build(/* mediaDrmCallback= */ licenseServer); .build(/* mediaDrmCallback= */ licenseServer);
drmSessionManager.prepare(); drmSessionManager.prepare();
drmSessionManager.setPlayer(/* playbackLooper= */ Looper.myLooper(), PlayerId.UNSET);
DrmSession drmSession = DrmSession drmSession =
checkNotNull( checkNotNull(
drmSessionManager.acquireSession( drmSessionManager.acquireSession(
/* playbackLooper= */ checkNotNull(Looper.myLooper()), /* eventDispatcher= */ null, FORMAT_WITH_DRM_INIT_DATA));
/* eventDispatcher= */ null,
FORMAT_WITH_DRM_INIT_DATA));
waitForOpenedWithKeys(drmSession); waitForOpenedWithKeys(drmSession);
assertThat(drmSession.getState()).isEqualTo(DrmSession.STATE_OPENED_WITH_KEYS); assertThat(drmSession.getState()).isEqualTo(DrmSession.STATE_OPENED_WITH_KEYS);
@ -92,12 +92,11 @@ public class DefaultDrmSessionManagerTest {
.build(/* mediaDrmCallback= */ licenseServer); .build(/* mediaDrmCallback= */ licenseServer);
drmSessionManager.prepare(); drmSessionManager.prepare();
drmSessionManager.setPlayer(/* playbackLooper= */ Looper.myLooper(), PlayerId.UNSET);
DrmSession drmSession = DrmSession drmSession =
checkNotNull( checkNotNull(
drmSessionManager.acquireSession( drmSessionManager.acquireSession(
/* playbackLooper= */ checkNotNull(Looper.myLooper()), /* eventDispatcher= */ null, FORMAT_WITH_DRM_INIT_DATA));
/* eventDispatcher= */ null,
FORMAT_WITH_DRM_INIT_DATA));
waitForOpenedWithKeys(drmSession); waitForOpenedWithKeys(drmSession);
assertThat(drmSession.getState()).isEqualTo(DrmSession.STATE_OPENED_WITH_KEYS); assertThat(drmSession.getState()).isEqualTo(DrmSession.STATE_OPENED_WITH_KEYS);
@ -118,12 +117,11 @@ public class DefaultDrmSessionManagerTest {
.build(/* mediaDrmCallback= */ licenseServer); .build(/* mediaDrmCallback= */ licenseServer);
drmSessionManager.prepare(); drmSessionManager.prepare();
drmSessionManager.setPlayer(/* playbackLooper= */ Looper.myLooper(), PlayerId.UNSET);
DrmSession drmSession = DrmSession drmSession =
checkNotNull( checkNotNull(
drmSessionManager.acquireSession( drmSessionManager.acquireSession(
/* playbackLooper= */ checkNotNull(Looper.myLooper()), /* eventDispatcher= */ null, FORMAT_WITH_DRM_INIT_DATA));
/* eventDispatcher= */ null,
FORMAT_WITH_DRM_INIT_DATA));
waitForOpenedWithKeys(drmSession); waitForOpenedWithKeys(drmSession);
drmSession.release(/* eventDispatcher= */ null); drmSession.release(/* eventDispatcher= */ null);
@ -141,12 +139,11 @@ public class DefaultDrmSessionManagerTest {
.build(/* mediaDrmCallback= */ licenseServer); .build(/* mediaDrmCallback= */ licenseServer);
drmSessionManager.prepare(); drmSessionManager.prepare();
drmSessionManager.setPlayer(/* playbackLooper= */ Looper.myLooper(), PlayerId.UNSET);
DrmSession drmSession = DrmSession drmSession =
checkNotNull( checkNotNull(
drmSessionManager.acquireSession( drmSessionManager.acquireSession(
/* playbackLooper= */ checkNotNull(Looper.myLooper()), /* eventDispatcher= */ null, FORMAT_WITH_DRM_INIT_DATA));
/* eventDispatcher= */ null,
FORMAT_WITH_DRM_INIT_DATA));
waitForOpenedWithKeys(drmSession); waitForOpenedWithKeys(drmSession);
drmSession.release(/* eventDispatcher= */ null); drmSession.release(/* eventDispatcher= */ null);
@ -166,12 +163,11 @@ public class DefaultDrmSessionManagerTest {
.build(/* mediaDrmCallback= */ licenseServer); .build(/* mediaDrmCallback= */ licenseServer);
drmSessionManager.prepare(); drmSessionManager.prepare();
drmSessionManager.setPlayer(/* playbackLooper= */ Looper.myLooper(), PlayerId.UNSET);
DrmSession drmSession = DrmSession drmSession =
checkNotNull( checkNotNull(
drmSessionManager.acquireSession( drmSessionManager.acquireSession(
/* playbackLooper= */ checkNotNull(Looper.myLooper()), /* eventDispatcher= */ null, FORMAT_WITH_DRM_INIT_DATA));
/* eventDispatcher= */ null,
FORMAT_WITH_DRM_INIT_DATA));
waitForOpenedWithKeys(drmSession); waitForOpenedWithKeys(drmSession);
assertThat(drmSession.getState()).isEqualTo(DrmSession.STATE_OPENED_WITH_KEYS); assertThat(drmSession.getState()).isEqualTo(DrmSession.STATE_OPENED_WITH_KEYS);
@ -193,12 +189,11 @@ public class DefaultDrmSessionManagerTest {
.build(/* mediaDrmCallback= */ licenseServer); .build(/* mediaDrmCallback= */ licenseServer);
drmSessionManager.prepare(); drmSessionManager.prepare();
drmSessionManager.setPlayer(/* playbackLooper= */ Looper.myLooper(), PlayerId.UNSET);
DrmSession drmSession = DrmSession drmSession =
checkNotNull( checkNotNull(
drmSessionManager.acquireSession( drmSessionManager.acquireSession(
/* playbackLooper= */ checkNotNull(Looper.myLooper()), /* eventDispatcher= */ null, FORMAT_WITH_DRM_INIT_DATA));
/* eventDispatcher= */ null,
FORMAT_WITH_DRM_INIT_DATA));
drmSessionManager.release(); drmSessionManager.release();
// The manager is now in a 'releasing' state because the session is still active - so the // The manager is now in a 'releasing' state because the session is still active - so the
@ -239,12 +234,11 @@ public class DefaultDrmSessionManagerTest {
.build(/* mediaDrmCallback= */ licenseServer); .build(/* mediaDrmCallback= */ licenseServer);
drmSessionManager.prepare(); drmSessionManager.prepare();
drmSessionManager.setPlayer(/* playbackLooper= */ Looper.myLooper(), PlayerId.UNSET);
DrmSession drmSession = DrmSession drmSession =
checkNotNull( checkNotNull(
drmSessionManager.acquireSession( drmSessionManager.acquireSession(
/* playbackLooper= */ checkNotNull(Looper.myLooper()), /* eventDispatcher= */ null, FORMAT_WITH_DRM_INIT_DATA));
/* eventDispatcher= */ null,
FORMAT_WITH_DRM_INIT_DATA));
waitForOpenedWithKeys(drmSession); waitForOpenedWithKeys(drmSession);
// Release the manager (there's still an explicit reference to the session from acquireSession). // Release the manager (there's still an explicit reference to the session from acquireSession).
@ -279,12 +273,11 @@ public class DefaultDrmSessionManagerTest {
.build(/* mediaDrmCallback= */ licenseServer); .build(/* mediaDrmCallback= */ licenseServer);
drmSessionManager.prepare(); drmSessionManager.prepare();
drmSessionManager.setPlayer(/* playbackLooper= */ Looper.myLooper(), PlayerId.UNSET);
DrmSession firstDrmSession = DrmSession firstDrmSession =
checkNotNull( checkNotNull(
drmSessionManager.acquireSession( drmSessionManager.acquireSession(
/* playbackLooper= */ checkNotNull(Looper.myLooper()), /* eventDispatcher= */ null, FORMAT_WITH_DRM_INIT_DATA));
/* eventDispatcher= */ null,
FORMAT_WITH_DRM_INIT_DATA));
waitForOpenedWithKeys(firstDrmSession); waitForOpenedWithKeys(firstDrmSession);
firstDrmSession.release(/* eventDispatcher= */ null); firstDrmSession.release(/* eventDispatcher= */ null);
@ -294,9 +287,7 @@ public class DefaultDrmSessionManagerTest {
DrmSession secondDrmSession = DrmSession secondDrmSession =
checkNotNull( checkNotNull(
drmSessionManager.acquireSession( drmSessionManager.acquireSession(
/* playbackLooper= */ checkNotNull(Looper.myLooper()), /* eventDispatcher= */ null, secondFormatWithDrmInitData));
/* eventDispatcher= */ null,
secondFormatWithDrmInitData));
// The drmSessionManager had to release firstDrmSession in order to acquire secondDrmSession. // The drmSessionManager had to release firstDrmSession in order to acquire secondDrmSession.
assertThat(firstDrmSession.getState()).isEqualTo(DrmSession.STATE_RELEASED); assertThat(firstDrmSession.getState()).isEqualTo(DrmSession.STATE_RELEASED);
@ -323,18 +314,15 @@ public class DefaultDrmSessionManagerTest {
.build(/* mediaDrmCallback= */ licenseServer); .build(/* mediaDrmCallback= */ licenseServer);
drmSessionManager.prepare(); drmSessionManager.prepare();
drmSessionManager.setPlayer(/* playbackLooper= */ Looper.myLooper(), PlayerId.UNSET);
DrmSessionReference firstDrmSessionReference = DrmSessionReference firstDrmSessionReference =
checkNotNull( checkNotNull(
drmSessionManager.preacquireSession( drmSessionManager.preacquireSession(
/* playbackLooper= */ checkNotNull(Looper.myLooper()), /* eventDispatcher= */ null, FORMAT_WITH_DRM_INIT_DATA));
/* eventDispatcher= */ null,
FORMAT_WITH_DRM_INIT_DATA));
DrmSession firstDrmSession = DrmSession firstDrmSession =
checkNotNull( checkNotNull(
drmSessionManager.acquireSession( drmSessionManager.acquireSession(
/* playbackLooper= */ checkNotNull(Looper.myLooper()), /* eventDispatcher= */ null, FORMAT_WITH_DRM_INIT_DATA));
/* eventDispatcher= */ null,
FORMAT_WITH_DRM_INIT_DATA));
waitForOpenedWithKeys(firstDrmSession); waitForOpenedWithKeys(firstDrmSession);
firstDrmSession.release(/* eventDispatcher= */ null); firstDrmSession.release(/* eventDispatcher= */ null);
@ -344,9 +332,7 @@ public class DefaultDrmSessionManagerTest {
DrmSession secondDrmSession = DrmSession secondDrmSession =
checkNotNull( checkNotNull(
drmSessionManager.acquireSession( drmSessionManager.acquireSession(
/* playbackLooper= */ checkNotNull(Looper.myLooper()), /* eventDispatcher= */ null, secondFormatWithDrmInitData));
/* eventDispatcher= */ null,
secondFormatWithDrmInitData));
// The drmSessionManager had to release both it's internal keep-alive reference and the // The drmSessionManager had to release both it's internal keep-alive reference and the
// reference represented by firstDrmSessionReference in order to acquire secondDrmSession. // reference represented by firstDrmSessionReference in order to acquire secondDrmSession.
assertThat(firstDrmSession.getState()).isEqualTo(DrmSession.STATE_RELEASED); assertThat(firstDrmSession.getState()).isEqualTo(DrmSession.STATE_RELEASED);
@ -373,12 +359,11 @@ public class DefaultDrmSessionManagerTest {
.build(/* mediaDrmCallback= */ licenseServer); .build(/* mediaDrmCallback= */ licenseServer);
drmSessionManager.prepare(); drmSessionManager.prepare();
drmSessionManager.setPlayer(/* playbackLooper= */ Looper.myLooper(), PlayerId.UNSET);
DrmSession firstDrmSession = DrmSession firstDrmSession =
checkNotNull( checkNotNull(
drmSessionManager.acquireSession( drmSessionManager.acquireSession(
/* playbackLooper= */ checkNotNull(Looper.myLooper()), /* eventDispatcher= */ null, FORMAT_WITH_DRM_INIT_DATA));
/* eventDispatcher= */ null,
FORMAT_WITH_DRM_INIT_DATA));
waitForOpenedWithKeys(firstDrmSession); waitForOpenedWithKeys(firstDrmSession);
firstDrmSession.release(/* eventDispatcher= */ null); firstDrmSession.release(/* eventDispatcher= */ null);
@ -389,9 +374,7 @@ public class DefaultDrmSessionManagerTest {
DrmSession secondDrmSession = DrmSession secondDrmSession =
checkNotNull( checkNotNull(
drmSessionManager.acquireSession( drmSessionManager.acquireSession(
/* playbackLooper= */ checkNotNull(Looper.myLooper()), /* eventDispatcher= */ null, FORMAT_WITH_DRM_INIT_DATA));
/* eventDispatcher= */ null,
FORMAT_WITH_DRM_INIT_DATA));
assertThat(secondDrmSession).isSameInstanceAs(firstDrmSession); assertThat(secondDrmSession).isSameInstanceAs(firstDrmSession);
// Let the timeout definitely expire, and check the session didn't get released. // Let the timeout definitely expire, and check the session didn't get released.
@ -423,12 +406,10 @@ public class DefaultDrmSessionManagerTest {
.build(/* mediaDrmCallback= */ licenseServer); .build(/* mediaDrmCallback= */ licenseServer);
drmSessionManager.prepare(); drmSessionManager.prepare();
drmSessionManager.setPlayer(/* playbackLooper= */ Looper.myLooper(), PlayerId.UNSET);
DrmSessionReference sessionReference = DrmSessionReference sessionReference =
drmSessionManager.preacquireSession( drmSessionManager.preacquireSession(eventDispatcher, FORMAT_WITH_DRM_INIT_DATA);
/* playbackLooper= */ checkNotNull(Looper.myLooper()),
eventDispatcher,
FORMAT_WITH_DRM_INIT_DATA);
// Wait for the key load event to propagate, indicating the pre-acquired session is in // Wait for the key load event to propagate, indicating the pre-acquired session is in
// STATE_OPENED_WITH_KEYS. // STATE_OPENED_WITH_KEYS.
@ -440,9 +421,7 @@ public class DefaultDrmSessionManagerTest {
DrmSession drmSession = DrmSession drmSession =
checkNotNull( checkNotNull(
drmSessionManager.acquireSession( drmSessionManager.acquireSession(
/* playbackLooper= */ checkNotNull(Looper.myLooper()), /* eventDispatcher= */ null, FORMAT_WITH_DRM_INIT_DATA));
/* eventDispatcher= */ null,
FORMAT_WITH_DRM_INIT_DATA));
// Without idling the main/playback looper, we assert the session is already in OPENED_WITH_KEYS // Without idling the main/playback looper, we assert the session is already in OPENED_WITH_KEYS
assertThat(drmSession.getState()).isEqualTo(DrmSession.STATE_OPENED_WITH_KEYS); assertThat(drmSession.getState()).isEqualTo(DrmSession.STATE_OPENED_WITH_KEYS);
@ -472,12 +451,10 @@ public class DefaultDrmSessionManagerTest {
.build(/* mediaDrmCallback= */ licenseServer); .build(/* mediaDrmCallback= */ licenseServer);
drmSessionManager.prepare(); drmSessionManager.prepare();
drmSessionManager.setPlayer(/* playbackLooper= */ Looper.myLooper(), PlayerId.UNSET);
DrmSessionReference sessionReference = DrmSessionReference sessionReference =
drmSessionManager.preacquireSession( drmSessionManager.preacquireSession(/* eventDispatcher= */ null, FORMAT_WITH_DRM_INIT_DATA);
/* playbackLooper= */ checkNotNull(Looper.myLooper()),
/* eventDispatcher= */ null,
FORMAT_WITH_DRM_INIT_DATA);
// Release the pre-acquired reference before the underlying session has had a chance to be // Release the pre-acquired reference before the underlying session has had a chance to be
// constructed. // constructed.
@ -488,9 +465,7 @@ public class DefaultDrmSessionManagerTest {
DrmSession drmSession = DrmSession drmSession =
checkNotNull( checkNotNull(
drmSessionManager.acquireSession( drmSessionManager.acquireSession(
/* playbackLooper= */ checkNotNull(Looper.myLooper()), /* eventDispatcher= */ null, FORMAT_WITH_DRM_INIT_DATA));
/* eventDispatcher= */ null,
FORMAT_WITH_DRM_INIT_DATA));
assertThat(drmSession.getState()).isEqualTo(DrmSession.STATE_OPENED); assertThat(drmSession.getState()).isEqualTo(DrmSession.STATE_OPENED);
waitForOpenedWithKeys(drmSession); waitForOpenedWithKeys(drmSession);
@ -512,12 +487,10 @@ public class DefaultDrmSessionManagerTest {
.build(/* mediaDrmCallback= */ licenseServer); .build(/* mediaDrmCallback= */ licenseServer);
drmSessionManager.prepare(); drmSessionManager.prepare();
drmSessionManager.setPlayer(/* playbackLooper= */ Looper.myLooper(), PlayerId.UNSET);
DrmSessionReference sessionReference = DrmSessionReference sessionReference =
drmSessionManager.preacquireSession( drmSessionManager.preacquireSession(/* eventDispatcher= */ null, FORMAT_WITH_DRM_INIT_DATA);
/* playbackLooper= */ checkNotNull(Looper.myLooper()),
/* eventDispatcher= */ null,
FORMAT_WITH_DRM_INIT_DATA);
// Release the manager before the underlying session has had a chance to be constructed. This // Release the manager before the underlying session has had a chance to be constructed. This
// will release all pre-acquired sessions. // will release all pre-acquired sessions.
@ -532,9 +505,7 @@ public class DefaultDrmSessionManagerTest {
DrmSession drmSession = DrmSession drmSession =
checkNotNull( checkNotNull(
drmSessionManager.acquireSession( drmSessionManager.acquireSession(
/* playbackLooper= */ checkNotNull(Looper.myLooper()), /* eventDispatcher= */ null, FORMAT_WITH_DRM_INIT_DATA));
/* eventDispatcher= */ null,
FORMAT_WITH_DRM_INIT_DATA));
assertThat(drmSession.getState()).isEqualTo(DrmSession.STATE_OPENED); assertThat(drmSession.getState()).isEqualTo(DrmSession.STATE_OPENED);
waitForOpenedWithKeys(drmSession); waitForOpenedWithKeys(drmSession);
@ -560,14 +531,13 @@ public class DefaultDrmSessionManagerTest {
.build(/* mediaDrmCallback= */ licenseServer); .build(/* mediaDrmCallback= */ licenseServer);
drmSessionManager.prepare(); drmSessionManager.prepare();
drmSessionManager.setPlayer(/* playbackLooper= */ Looper.myLooper(), PlayerId.UNSET);
DefaultDrmSession drmSession = DefaultDrmSession drmSession =
(DefaultDrmSession) (DefaultDrmSession)
checkNotNull( checkNotNull(
drmSessionManager.acquireSession( drmSessionManager.acquireSession(
/* playbackLooper= */ checkNotNull(Looper.myLooper()), /* eventDispatcher= */ null, FORMAT_WITH_DRM_INIT_DATA));
/* eventDispatcher= */ null,
FORMAT_WITH_DRM_INIT_DATA));
waitForOpenedWithKeys(drmSession); waitForOpenedWithKeys(drmSession);
assertThat(licenseServer.getReceivedSchemeDatas()).hasSize(1); assertThat(licenseServer.getReceivedSchemeDatas()).hasSize(1);
@ -602,14 +572,13 @@ public class DefaultDrmSessionManagerTest {
.build(/* mediaDrmCallback= */ licenseServer); .build(/* mediaDrmCallback= */ licenseServer);
drmSessionManager.prepare(); drmSessionManager.prepare();
drmSessionManager.setPlayer(/* playbackLooper= */ Looper.myLooper(), PlayerId.UNSET);
DefaultDrmSession drmSession = DefaultDrmSession drmSession =
(DefaultDrmSession) (DefaultDrmSession)
checkNotNull( checkNotNull(
drmSessionManager.acquireSession( drmSessionManager.acquireSession(
/* playbackLooper= */ checkNotNull(Looper.myLooper()), /* eventDispatcher= */ null, FORMAT_WITH_DRM_INIT_DATA));
/* eventDispatcher= */ null,
FORMAT_WITH_DRM_INIT_DATA));
waitForOpenedWithKeys(drmSession); waitForOpenedWithKeys(drmSession);
assertThat(licenseServer.getReceivedSchemeDatas()).hasSize(1); assertThat(licenseServer.getReceivedSchemeDatas()).hasSize(1);
@ -647,12 +616,11 @@ public class DefaultDrmSessionManagerTest {
uuid -> new FakeExoMediaDrm.Builder().setProvisionsRequired(1).build()) uuid -> new FakeExoMediaDrm.Builder().setProvisionsRequired(1).build())
.build(/* mediaDrmCallback= */ licenseServer); .build(/* mediaDrmCallback= */ licenseServer);
drmSessionManager.prepare(); drmSessionManager.prepare();
drmSessionManager.setPlayer(/* playbackLooper= */ Looper.myLooper(), PlayerId.UNSET);
DrmSession drmSession = DrmSession drmSession =
checkNotNull( checkNotNull(
drmSessionManager.acquireSession( drmSessionManager.acquireSession(
/* playbackLooper= */ checkNotNull(Looper.myLooper()), /* eventDispatcher= */ null, FORMAT_WITH_DRM_INIT_DATA));
/* eventDispatcher= */ null,
FORMAT_WITH_DRM_INIT_DATA));
// Confirm that opening the session threw NotProvisionedException (otherwise state would be // Confirm that opening the session threw NotProvisionedException (otherwise state would be
// OPENED) // OPENED)
assertThat(drmSession.getState()).isEqualTo(DrmSession.STATE_OPENING); assertThat(drmSession.getState()).isEqualTo(DrmSession.STATE_OPENING);
@ -681,12 +649,11 @@ public class DefaultDrmSessionManagerTest {
.build()) .build())
.build(/* mediaDrmCallback= */ licenseServer); .build(/* mediaDrmCallback= */ licenseServer);
drmSessionManager.prepare(); drmSessionManager.prepare();
drmSessionManager.setPlayer(/* playbackLooper= */ Looper.myLooper(), PlayerId.UNSET);
DrmSession drmSession = DrmSession drmSession =
checkNotNull( checkNotNull(
drmSessionManager.acquireSession( drmSessionManager.acquireSession(
/* playbackLooper= */ checkNotNull(Looper.myLooper()), /* eventDispatcher= */ null, FORMAT_WITH_DRM_INIT_DATA));
/* eventDispatcher= */ null,
FORMAT_WITH_DRM_INIT_DATA));
assertThat(drmSession.getState()).isEqualTo(DrmSession.STATE_OPENED); assertThat(drmSession.getState()).isEqualTo(DrmSession.STATE_OPENED);
waitForOpenedWithKeys(drmSession); waitForOpenedWithKeys(drmSession);
@ -708,12 +675,11 @@ public class DefaultDrmSessionManagerTest {
uuid -> new FakeExoMediaDrm.Builder().setProvisionsRequired(2).build()) uuid -> new FakeExoMediaDrm.Builder().setProvisionsRequired(2).build())
.build(/* mediaDrmCallback= */ licenseServer); .build(/* mediaDrmCallback= */ licenseServer);
drmSessionManager.prepare(); drmSessionManager.prepare();
drmSessionManager.setPlayer(/* playbackLooper= */ Looper.myLooper(), PlayerId.UNSET);
DrmSession drmSession = DrmSession drmSession =
checkNotNull( checkNotNull(
drmSessionManager.acquireSession( drmSessionManager.acquireSession(
/* playbackLooper= */ checkNotNull(Looper.myLooper()), /* eventDispatcher= */ null, FORMAT_WITH_DRM_INIT_DATA));
/* eventDispatcher= */ null,
FORMAT_WITH_DRM_INIT_DATA));
// Confirm that opening the session threw NotProvisionedException (otherwise state would be // Confirm that opening the session threw NotProvisionedException (otherwise state would be
// OPENED) // OPENED)
assertThat(drmSession.getState()).isEqualTo(DrmSession.STATE_OPENING); assertThat(drmSession.getState()).isEqualTo(DrmSession.STATE_OPENING);
@ -737,12 +703,11 @@ public class DefaultDrmSessionManagerTest {
DRM_SCHEME_UUID, uuid -> new FakeExoMediaDrm.Builder().build()) DRM_SCHEME_UUID, uuid -> new FakeExoMediaDrm.Builder().build())
.build(/* mediaDrmCallback= */ licenseServer); .build(/* mediaDrmCallback= */ licenseServer);
drmSessionManager.prepare(); drmSessionManager.prepare();
drmSessionManager.setPlayer(/* playbackLooper= */ Looper.myLooper(), PlayerId.UNSET);
DrmSession drmSession = DrmSession drmSession =
checkNotNull( checkNotNull(
drmSessionManager.acquireSession( drmSessionManager.acquireSession(
/* playbackLooper= */ checkNotNull(Looper.myLooper()), /* eventDispatcher= */ null, FORMAT_WITH_DRM_INIT_DATA));
/* eventDispatcher= */ null,
FORMAT_WITH_DRM_INIT_DATA));
assertThat(drmSession.getState()).isEqualTo(DrmSession.STATE_OPENED); assertThat(drmSession.getState()).isEqualTo(DrmSession.STATE_OPENED);
waitForOpenedWithKeys(drmSession); waitForOpenedWithKeys(drmSession);
@ -764,12 +729,11 @@ public class DefaultDrmSessionManagerTest {
.setSessionKeepaliveMs(C.TIME_UNSET) .setSessionKeepaliveMs(C.TIME_UNSET)
.build(/* mediaDrmCallback= */ licenseServer); .build(/* mediaDrmCallback= */ licenseServer);
drmSessionManager.prepare(); drmSessionManager.prepare();
drmSessionManager.setPlayer(/* playbackLooper= */ Looper.myLooper(), PlayerId.UNSET);
DrmSession drmSession = DrmSession drmSession =
checkNotNull( checkNotNull(
drmSessionManager.acquireSession( drmSessionManager.acquireSession(
/* playbackLooper= */ checkNotNull(Looper.myLooper()), /* eventDispatcher= */ null, FORMAT_WITH_DRM_INIT_DATA));
/* eventDispatcher= */ null,
FORMAT_WITH_DRM_INIT_DATA));
// Confirm that opening the session threw NotProvisionedException (otherwise state would be // Confirm that opening the session threw NotProvisionedException (otherwise state would be
// OPENED) // OPENED)
assertThat(drmSession.getState()).isEqualTo(DrmSession.STATE_OPENING); assertThat(drmSession.getState()).isEqualTo(DrmSession.STATE_OPENING);
@ -781,9 +745,7 @@ public class DefaultDrmSessionManagerTest {
drmSession = drmSession =
checkNotNull( checkNotNull(
drmSessionManager.acquireSession( drmSessionManager.acquireSession(
/* playbackLooper= */ checkNotNull(Looper.myLooper()), /* eventDispatcher= */ null, FORMAT_WITH_DRM_INIT_DATA));
/* eventDispatcher= */ null,
FORMAT_WITH_DRM_INIT_DATA));
// Confirm that opening the session threw NotProvisionedException (otherwise state would be // Confirm that opening the session threw NotProvisionedException (otherwise state would be
// OPENED) // OPENED)
assertThat(drmSession.getState()).isEqualTo(DrmSession.STATE_OPENING); assertThat(drmSession.getState()).isEqualTo(DrmSession.STATE_OPENING);
@ -804,16 +766,12 @@ public class DefaultDrmSessionManagerTest {
Exception.class, Exception.class,
() -> () ->
drmSessionManager.acquireSession( drmSessionManager.acquireSession(
/* playbackLooper= */ checkNotNull(Looper.myLooper()), /* eventDispatcher= */ null, FORMAT_WITH_DRM_INIT_DATA));
/* eventDispatcher= */ null,
FORMAT_WITH_DRM_INIT_DATA));
assertThrows( assertThrows(
Exception.class, Exception.class,
() -> () ->
drmSessionManager.preacquireSession( drmSessionManager.preacquireSession(
/* playbackLooper= */ checkNotNull(Looper.myLooper()), /* eventDispatcher= */ null, FORMAT_WITH_DRM_INIT_DATA));
/* eventDispatcher= */ null,
FORMAT_WITH_DRM_INIT_DATA));
} }
@Test @Test
@ -826,12 +784,11 @@ public class DefaultDrmSessionManagerTest {
.build(/* mediaDrmCallback= */ licenseServer); .build(/* mediaDrmCallback= */ licenseServer);
drmSessionManager.prepare(); drmSessionManager.prepare();
drmSessionManager.setPlayer(/* playbackLooper= */ Looper.myLooper(), PlayerId.UNSET);
DrmSession drmSession = DrmSession drmSession =
checkNotNull( checkNotNull(
drmSessionManager.acquireSession( drmSessionManager.acquireSession(
/* playbackLooper= */ checkNotNull(Looper.myLooper()), /* eventDispatcher= */ null, FORMAT_WITH_DRM_INIT_DATA));
/* eventDispatcher= */ null,
FORMAT_WITH_DRM_INIT_DATA));
drmSessionManager.release(); drmSessionManager.release();
// The manager's prepareCount is now zero, but the drmSession is keeping it in a 'releasing' // The manager's prepareCount is now zero, but the drmSession is keeping it in a 'releasing'
@ -840,16 +797,12 @@ public class DefaultDrmSessionManagerTest {
Exception.class, Exception.class,
() -> () ->
drmSessionManager.acquireSession( drmSessionManager.acquireSession(
/* playbackLooper= */ checkNotNull(Looper.myLooper()), /* eventDispatcher= */ null, FORMAT_WITH_DRM_INIT_DATA));
/* eventDispatcher= */ null,
FORMAT_WITH_DRM_INIT_DATA));
assertThrows( assertThrows(
Exception.class, Exception.class,
() -> () ->
drmSessionManager.preacquireSession( drmSessionManager.preacquireSession(
/* playbackLooper= */ checkNotNull(Looper.myLooper()), /* eventDispatcher= */ null, FORMAT_WITH_DRM_INIT_DATA));
/* eventDispatcher= */ null,
FORMAT_WITH_DRM_INIT_DATA));
drmSession.release(/* eventDispatcher= */ null); drmSession.release(/* eventDispatcher= */ null);
} }

View File

@ -36,10 +36,10 @@ import androidx.media3.common.DrmInitData;
import androidx.media3.common.Format; import androidx.media3.common.Format;
import androidx.media3.common.MimeTypes; import androidx.media3.common.MimeTypes;
import androidx.media3.common.PlaybackException; import androidx.media3.common.PlaybackException;
import androidx.media3.common.util.Assertions;
import androidx.media3.common.util.ParsableByteArray; import androidx.media3.common.util.ParsableByteArray;
import androidx.media3.decoder.DecoderInputBuffer; import androidx.media3.decoder.DecoderInputBuffer;
import androidx.media3.exoplayer.FormatHolder; import androidx.media3.exoplayer.FormatHolder;
import androidx.media3.exoplayer.analytics.PlayerId;
import androidx.media3.exoplayer.drm.DrmSession; import androidx.media3.exoplayer.drm.DrmSession;
import androidx.media3.exoplayer.drm.DrmSessionEventListener; import androidx.media3.exoplayer.drm.DrmSessionEventListener;
import androidx.media3.exoplayer.drm.DrmSessionManager; import androidx.media3.exoplayer.drm.DrmSessionManager;
@ -146,12 +146,7 @@ public final class SampleQueueTest {
mockDrmSession = Mockito.mock(DrmSession.class); mockDrmSession = Mockito.mock(DrmSession.class);
mockDrmSessionManager = new MockDrmSessionManager(mockDrmSession); mockDrmSessionManager = new MockDrmSessionManager(mockDrmSession);
eventDispatcher = new DrmSessionEventListener.EventDispatcher(); eventDispatcher = new DrmSessionEventListener.EventDispatcher();
sampleQueue = sampleQueue = new SampleQueue(allocator, mockDrmSessionManager, eventDispatcher);
new SampleQueue(
allocator,
/* playbackLooper= */ Assertions.checkNotNull(Looper.myLooper()),
mockDrmSessionManager,
eventDispatcher);
formatHolder = new FormatHolder(); formatHolder = new FormatHolder();
inputBuffer = new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_NORMAL); inputBuffer = new DecoderInputBuffer(DecoderInputBuffer.BUFFER_REPLACEMENT_MODE_NORMAL);
} }
@ -424,12 +419,7 @@ public final class SampleQueueTest {
public void isReadyReturnsTrueForClearSampleAndPlayClearSamplesWithoutKeysIsTrue() { public void isReadyReturnsTrueForClearSampleAndPlayClearSamplesWithoutKeysIsTrue() {
when(mockDrmSession.playClearSamplesWithoutKeys()).thenReturn(true); when(mockDrmSession.playClearSamplesWithoutKeys()).thenReturn(true);
// We recreate the queue to ensure the mock DRM session manager flags are taken into account. // We recreate the queue to ensure the mock DRM session manager flags are taken into account.
sampleQueue = sampleQueue = new SampleQueue(allocator, mockDrmSessionManager, eventDispatcher);
new SampleQueue(
allocator,
/* playbackLooper= */ Assertions.checkNotNull(Looper.myLooper()),
mockDrmSessionManager,
eventDispatcher);
writeTestDataWithEncryptedSections(); writeTestDataWithEncryptedSections();
assertThat(sampleQueue.isReady(/* loadingFinished= */ false)).isTrue(); assertThat(sampleQueue.isReady(/* loadingFinished= */ false)).isTrue();
} }
@ -574,12 +564,7 @@ public final class SampleQueueTest {
public void allowPlayClearSamplesWithoutKeysReadsClearSamples() { public void allowPlayClearSamplesWithoutKeysReadsClearSamples() {
when(mockDrmSession.playClearSamplesWithoutKeys()).thenReturn(true); when(mockDrmSession.playClearSamplesWithoutKeys()).thenReturn(true);
// We recreate the queue to ensure the mock DRM session manager flags are taken into account. // We recreate the queue to ensure the mock DRM session manager flags are taken into account.
sampleQueue = sampleQueue = new SampleQueue(allocator, mockDrmSessionManager, eventDispatcher);
new SampleQueue(
allocator,
/* playbackLooper= */ Assertions.checkNotNull(Looper.myLooper()),
mockDrmSessionManager,
eventDispatcher);
when(mockDrmSession.getState()).thenReturn(DrmSession.STATE_OPENED); when(mockDrmSession.getState()).thenReturn(DrmSession.STATE_OPENED);
writeTestDataWithEncryptedSections(); writeTestDataWithEncryptedSections();
@ -1246,11 +1231,7 @@ public final class SampleQueueTest {
public void adjustUpstreamFormat() { public void adjustUpstreamFormat() {
String label = "label"; String label = "label";
sampleQueue = sampleQueue =
new SampleQueue( new SampleQueue(allocator, mockDrmSessionManager, eventDispatcher) {
allocator,
/* playbackLooper= */ Assertions.checkNotNull(Looper.myLooper()),
mockDrmSessionManager,
eventDispatcher) {
@Override @Override
public Format getAdjustedUpstreamFormat(Format format) { public Format getAdjustedUpstreamFormat(Format format) {
return super.getAdjustedUpstreamFormat(copyWithLabel(format, label)); return super.getAdjustedUpstreamFormat(copyWithLabel(format, label));
@ -1266,11 +1247,7 @@ public final class SampleQueueTest {
public void invalidateUpstreamFormatAdjustment() { public void invalidateUpstreamFormatAdjustment() {
AtomicReference<String> label = new AtomicReference<>("label1"); AtomicReference<String> label = new AtomicReference<>("label1");
sampleQueue = sampleQueue =
new SampleQueue( new SampleQueue(allocator, mockDrmSessionManager, eventDispatcher) {
allocator,
/* playbackLooper= */ Assertions.checkNotNull(Looper.myLooper()),
mockDrmSessionManager,
eventDispatcher) {
@Override @Override
public Format getAdjustedUpstreamFormat(Format format) { public Format getAdjustedUpstreamFormat(Format format) {
return super.getAdjustedUpstreamFormat(copyWithLabel(format, label.get())); return super.getAdjustedUpstreamFormat(copyWithLabel(format, label.get()));
@ -1770,12 +1747,13 @@ public final class SampleQueueTest {
this.mockDrmSession = mockDrmSession; this.mockDrmSession = mockDrmSession;
} }
@Override
public void setPlayer(Looper playbackLooper, PlayerId playerId) {}
@Override @Override
@Nullable @Nullable
public DrmSession acquireSession( public DrmSession acquireSession(
Looper playbackLooper, @Nullable DrmSessionEventListener.EventDispatcher eventDispatcher, Format format) {
@Nullable DrmSessionEventListener.EventDispatcher eventDispatcher,
Format format) {
return format.drmInitData != null ? mockDrmSession : mockPlaceholderDrmSession; return format.drmInitData != null ? mockDrmSession : mockPlaceholderDrmSession;
} }

View File

@ -22,6 +22,7 @@ import static java.lang.Math.min;
import android.net.Uri; import android.net.Uri;
import android.os.Handler; import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock; import android.os.SystemClock;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.SparseArray; import android.util.SparseArray;
@ -561,6 +562,7 @@ public final class DashMediaSource extends BaseMediaSource {
protected void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) { protected void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) {
this.mediaTransferListener = mediaTransferListener; this.mediaTransferListener = mediaTransferListener;
drmSessionManager.prepare(); drmSessionManager.prepare();
drmSessionManager.setPlayer(/* playbackLooper= */ Looper.myLooper(), getPlayerId());
if (sideloadedManifest) { if (sideloadedManifest) {
processManifest(false); processManifest(false);
} else { } else {

View File

@ -19,6 +19,7 @@ import static androidx.media3.common.util.Assertions.checkNotNull;
import static java.lang.annotation.RetentionPolicy.SOURCE; import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.net.Uri; import android.net.Uri;
import android.os.Looper;
import android.os.SystemClock; import android.os.SystemClock;
import androidx.annotation.IntDef; import androidx.annotation.IntDef;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
@ -468,6 +469,8 @@ public final class HlsMediaSource extends BaseMediaSource
protected void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) { protected void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) {
this.mediaTransferListener = mediaTransferListener; this.mediaTransferListener = mediaTransferListener;
drmSessionManager.prepare(); drmSessionManager.prepare();
drmSessionManager.setPlayer(
/* playbackLooper= */ checkNotNull(Looper.myLooper()), getPlayerId());
MediaSourceEventListener.EventDispatcher eventDispatcher = MediaSourceEventListener.EventDispatcher eventDispatcher =
createEventDispatcher(/* mediaPeriodId= */ null); createEventDispatcher(/* mediaPeriodId= */ null);
playlistTracker.start( playlistTracker.start(

View File

@ -23,7 +23,6 @@ import static java.lang.Math.min;
import android.net.Uri; import android.net.Uri;
import android.os.Handler; import android.os.Handler;
import android.os.Looper;
import android.util.SparseIntArray; import android.util.SparseIntArray;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.media3.common.C; import androidx.media3.common.C;
@ -1100,12 +1099,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
boolean isAudioVideo = type == C.TRACK_TYPE_AUDIO || type == C.TRACK_TYPE_VIDEO; boolean isAudioVideo = type == C.TRACK_TYPE_AUDIO || type == C.TRACK_TYPE_VIDEO;
HlsSampleQueue sampleQueue = HlsSampleQueue sampleQueue =
new HlsSampleQueue( new HlsSampleQueue(allocator, drmSessionManager, drmEventDispatcher, overridingDrmInitData);
allocator,
/* playbackLooper= */ handler.getLooper(),
drmSessionManager,
drmEventDispatcher,
overridingDrmInitData);
sampleQueue.setStartTimeUs(lastSeekPositionUs); sampleQueue.setStartTimeUs(lastSeekPositionUs);
if (isAudioVideo) { if (isAudioVideo) {
sampleQueue.setDrmInitData(drmInitData); sampleQueue.setDrmInitData(drmInitData);
@ -1639,11 +1633,10 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
private HlsSampleQueue( private HlsSampleQueue(
Allocator allocator, Allocator allocator,
Looper playbackLooper,
DrmSessionManager drmSessionManager, DrmSessionManager drmSessionManager,
DrmSessionEventListener.EventDispatcher eventDispatcher, DrmSessionEventListener.EventDispatcher eventDispatcher,
Map<String, DrmInitData> overridingDrmInitData) { Map<String, DrmInitData> overridingDrmInitData) {
super(allocator, playbackLooper, drmSessionManager, eventDispatcher); super(allocator, drmSessionManager, eventDispatcher);
this.overridingDrmInitData = overridingDrmInitData; this.overridingDrmInitData = overridingDrmInitData;
} }

View File

@ -21,6 +21,7 @@ import static java.lang.Math.min;
import android.net.Uri; import android.net.Uri;
import android.os.Handler; import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock; import android.os.SystemClock;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.media3.common.C; import androidx.media3.common.C;
@ -438,6 +439,7 @@ public final class SsMediaSource extends BaseMediaSource
protected void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) { protected void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) {
this.mediaTransferListener = mediaTransferListener; this.mediaTransferListener = mediaTransferListener;
drmSessionManager.prepare(); drmSessionManager.prepare();
drmSessionManager.setPlayer(/* playbackLooper= */ Looper.myLooper(), getPlayerId());
if (sideloadedManifest) { if (sideloadedManifest) {
manifestLoaderErrorThrower = new LoaderErrorThrower.Dummy(); manifestLoaderErrorThrower = new LoaderErrorThrower.Dummy();
processManifest(); processManifest();

View File

@ -15,11 +15,13 @@
*/ */
package androidx.media3.test.utils; package androidx.media3.test.utils;
import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.common.util.Assertions.checkState; import static androidx.media3.common.util.Assertions.checkState;
import static androidx.media3.common.util.Util.castNonNull; import static androidx.media3.common.util.Util.castNonNull;
import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertThat;
import android.os.Handler; import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock; import android.os.SystemClock;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.media3.common.C; import androidx.media3.common.C;
@ -214,6 +216,8 @@ public class FakeMediaSource extends BaseMediaSource {
assertThat(preparedSource).isFalse(); assertThat(preparedSource).isFalse();
transferListener = mediaTransferListener; transferListener = mediaTransferListener;
drmSessionManager.prepare(); drmSessionManager.prepare();
drmSessionManager.setPlayer(
/* playbackLooper= */ checkNotNull(Looper.myLooper()), getPlayerId());
preparedSource = true; preparedSource = true;
releasedSource = false; releasedSource = false;
sourceInfoRefreshHandler = Util.createHandlerForCurrentLooper(); sourceInfoRefreshHandler = Util.createHandlerForCurrentLooper();

View File

@ -17,7 +17,6 @@ package androidx.media3.test.utils;
import static androidx.media3.common.util.Assertions.checkNotNull; import static androidx.media3.common.util.Assertions.checkNotNull;
import android.os.Looper;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.media3.common.C; import androidx.media3.common.C;
import androidx.media3.common.Format; import androidx.media3.common.Format;
@ -138,12 +137,7 @@ public class FakeSampleStream implements SampleStream {
DrmSessionEventListener.EventDispatcher drmEventDispatcher, DrmSessionEventListener.EventDispatcher drmEventDispatcher,
Format initialFormat, Format initialFormat,
List<FakeSampleStreamItem> fakeSampleStreamItems) { List<FakeSampleStreamItem> fakeSampleStreamItems) {
this.sampleQueue = this.sampleQueue = SampleQueue.createWithDrm(allocator, drmSessionManager, drmEventDispatcher);
SampleQueue.createWithDrm(
allocator,
/* playbackLooper= */ checkNotNull(Looper.myLooper()),
drmSessionManager,
drmEventDispatcher);
this.mediaSourceEventDispatcher = mediaSourceEventDispatcher; this.mediaSourceEventDispatcher = mediaSourceEventDispatcher;
this.sampleStreamItems = new ArrayList<>(); this.sampleStreamItems = new ArrayList<>();
sampleStreamItems.add(FakeSampleStreamItem.format(initialFormat)); sampleStreamItems.add(FakeSampleStreamItem.format(initialFormat));