DrmSessionManager.java
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.media3.exoplayer.drm;
import android.os.Looper;
import androidx.annotation.Nullable;
import androidx.media3.common.C;
import androidx.media3.common.Format;
import androidx.media3.common.PlaybackException;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.exoplayer.analytics.PlayerId;
/** Manages a DRM session. */
@UnstableApi
public interface DrmSessionManager {
/**
* Represents a single reference count of a {@link DrmSession}, while deliberately not giving
* access to the underlying session.
*/
interface DrmSessionReference {
/** A reference that is never populated with an underlying {@link DrmSession}. */
DrmSessionReference EMPTY = () -> {};
/**
* Releases the underlying session at most once.
*
* <p>Can be called from any thread. Calling this method more than once will only release the
* underlying session once.
*/
void release();
}
/** An instance that supports no DRM schemes. */
DrmSessionManager DRM_UNSUPPORTED =
new DrmSessionManager() {
@Override
public void setPlayer(Looper playbackLooper, PlayerId playerId) {}
@Override
@Nullable
public DrmSession acquireSession(
@Nullable DrmSessionEventListener.EventDispatcher eventDispatcher, Format format) {
if (format.drmInitData == null) {
return null;
} else {
return new ErrorStateDrmSession(
new DrmSession.DrmSessionException(
new UnsupportedDrmException(UnsupportedDrmException.REASON_UNSUPPORTED_SCHEME),
PlaybackException.ERROR_CODE_DRM_SCHEME_UNSUPPORTED));
}
}
@Override
public @C.CryptoType int getCryptoType(Format format) {
return format.drmInitData != null ? C.CRYPTO_TYPE_UNSUPPORTED : C.CRYPTO_TYPE_NONE;
}
};
/**
* An instance that supports no DRM schemes.
*
* @deprecated Use {@link #DRM_UNSUPPORTED}.
*/
@Deprecated DrmSessionManager DUMMY = DRM_UNSUPPORTED;
/**
* Returns {@link #DRM_UNSUPPORTED}.
*
* @deprecated Use {@link #DRM_UNSUPPORTED}.
*/
@Deprecated
static DrmSessionManager getDummyDrmSessionManager() {
return DRM_UNSUPPORTED;
}
/**
* Acquires any required resources.
*
* <p>{@link #release()} must be called to ensure the acquired resources are released. After
* releasing, an instance may be re-prepared.
*/
default void prepare() {
// Do nothing.
}
/** Releases any acquired resources. */
default void release() {
// 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}.
*
* <p>This notifies the manager that a subsequent call to {@link #acquireSession(
* DrmSessionEventListener.EventDispatcher, Format)} with the same {@link Format} is likely,
* allowing a manager that supports pre-acquisition to get the required {@link DrmSession} ready
* in the background.
*
* <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
* to {@link #acquireSession(DrmSessionEventListener.EventDispatcher, Format)} in the near
* future).
*
* <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(
* DrmSessionEventListener.EventDispatcher, Format)} re-initializing a new session, including
* repeating key loads and other async initialization steps.
*
* <p>The caller must separately call {@link #acquireSession(
* DrmSessionEventListener.EventDispatcher, Format)} in order to obtain a session suitable for
* playback. The pre-acquired {@link DrmSessionReference} and full {@link DrmSession} instances
* are distinct. The caller must release both, and can release the {@link DrmSessionReference}
* before the {@link DrmSession} without affecting playback.
*
* <p>This can be called from any thread.
*
* <p>Implementations that do not support pre-acquisition always return an empty {@link
* DrmSessionReference} instance.
*
* @param eventDispatcher The {@link DrmSessionEventListener.EventDispatcher} used to distribute
* events, and passed on to {@link
* DrmSession#acquire(DrmSessionEventListener.EventDispatcher)}.
* @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
* {@link #acquireSession(DrmSessionEventListener.EventDispatcher, Format)} would return null.
*/
default DrmSessionReference preacquireSession(
@Nullable DrmSessionEventListener.EventDispatcher eventDispatcher, Format format) {
return DrmSessionReference.EMPTY;
}
/**
* Returns a {@link DrmSession} for the specified {@link Format}, with an incremented reference
* count. May return null if the {@link Format#drmInitData} is null and the DRM session manager is
* not configured to attach a {@link DrmSession} to clear content. When the caller no longer needs
* to use a returned {@link DrmSession}, it must call {@link
* DrmSession#release(DrmSessionEventListener.EventDispatcher)} to decrement the reference count.
*
* <p>If the provided {@link Format} contains a null {@link Format#drmInitData}, the returned
* {@link DrmSession} (if not null) will be a placeholder session which does not execute key
* requests, and cannot be used to handle encrypted content. However, a placeholder session may be
* used to configure secure decoders for playback of clear content periods, which can reduce the
* cost of transitioning between clear and encrypted content.
*
* @param eventDispatcher The {@link DrmSessionEventListener.EventDispatcher} used to distribute
* events, and passed on to {@link
* DrmSession#acquire(DrmSessionEventListener.EventDispatcher)}.
* @param format The {@link Format} for which to acquire a {@link DrmSession}.
* @return The DRM session. May be null if the given {@link Format#drmInitData} is null.
*/
@Nullable
DrmSession acquireSession(
@Nullable DrmSessionEventListener.EventDispatcher eventDispatcher, Format format);
/**
* Returns the {@link C.CryptoType} that the DRM session manager will use for a given {@link
* Format}. Returns {@link C#CRYPTO_TYPE_UNSUPPORTED} if the manager does not support any of the
* DRM schemes defined in the {@link Format}. Returns {@link C#CRYPTO_TYPE_NONE} if {@link
* Format#drmInitData} is null and {@link #acquireSession} will return {@code null} for the given
* {@link Format}.
*
* @param format The {@link Format}.
* @return The {@link C.CryptoType} that the manager will use, or @link C#CRYPTO_TYPE_UNSUPPORTED}
* if the manager does not support any of the DRM schemes defined in the {@link Format}. Will
* be {@link C#CRYPTO_TYPE_NONE} if {@link Format#drmInitData} is null and {@link
* #acquireSession} will return null for the given {@link Format}.
*/
@C.CryptoType
int getCryptoType(Format format);
}