public interface

ExoMediaDrm

 androidx.media3.exoplayer.drm.ExoMediaDrm

Subclasses:

DummyExoMediaDrm, FrameworkMediaDrm, FakeExoMediaDrm

Gradle dependencies

compile group: 'androidx.media3', name: 'media3-exoplayer', version: '1.5.0-alpha01'

  • groupId: androidx.media3
  • artifactId: media3-exoplayer
  • version: 1.5.0-alpha01

Artifact androidx.media3:media3-exoplayer:1.5.0-alpha01 it located at Google repository (https://maven.google.com/)

Overview

Used to obtain keys for decrypting protected media streams.

Reference counting

Access to an instance is managed by reference counting, where ExoMediaDrm.acquire() increments the reference count and ExoMediaDrm.release() decrements it. When the reference count drops to 0 underlying resources are released, and the instance cannot be re-used.

Each new instance has an initial reference count of 1. Hence application code that creates a new instance does not normally need to call ExoMediaDrm.acquire(), and must call ExoMediaDrm.release() when the instance is no longer required.

Summary

Fields
public static final intEVENT_KEY_EXPIRED

Event indicating that keys have expired, and are no longer usable.

public static final intEVENT_KEY_REQUIRED

Event indicating that keys need to be requested from the license server.

public static final intEVENT_PROVISION_REQUIRED

Event indicating that a certificate needs to be requested from the provisioning server.

public static final intKEY_TYPE_OFFLINE

Key request type for keys that will be used for offline use.

public static final intKEY_TYPE_RELEASE

Key request type indicating that saved offline keys should be released.

public static final intKEY_TYPE_STREAMING

Key request type for keys that will be used for online use.

Methods
public voidacquire()

Increments the reference count.

public voidcloseSession(byte[] sessionId[])

Closes a DRM session.

public CryptoConfigcreateCryptoConfig(byte[] sessionId[])

Creates a CryptoConfig that can be passed to a compatible decoder to allow decryption of protected content using the specified session.

public intgetCryptoType()

Returns the of CryptoConfig instances returned by ExoMediaDrm.createCryptoConfig(byte[]).

public ExoMediaDrm.KeyRequestgetKeyRequest(byte[] scope[], java.util.List<DrmInitData.SchemeData> schemeDatas, int keyType, java.util.HashMap<java.lang.String, java.lang.String> optionalParameters)

Generates a key request.

public PersistableBundlegetMetrics()

Returns metrics data for this ExoMediaDrm instance, or null if metrics are unavailable.

public java.util.List<UnknownReference>getOfflineLicenseKeySetIds()

Returns a list of the keySetIds for all offline licenses.

public byte[]getPropertyByteArray(java.lang.String propertyName)

Returns the value of a byte array property.

public java.lang.StringgetPropertyString(java.lang.String propertyName)

Returns the value of a string property.

public ExoMediaDrm.ProvisionRequestgetProvisionRequest()

Generates a provisioning request.

public byte[]openSession()

Opens a new DRM session.

public byte[]provideKeyResponse(byte[] scope[], byte[] response[])

Provides a key response for the last request to be generated using ExoMediaDrm.getKeyRequest(byte[], List, int, HashMap).

public voidprovideProvisionResponse(byte[] response[])

Provides a provisioning response for the last request to be generated using ExoMediaDrm.getProvisionRequest().

public java.util.Map<java.lang.String, java.lang.String>queryKeyStatus(byte[] sessionId[])

Returns the key status for a given session, as {name, value} pairs.

public voidrelease()

Decrements the reference count.

public voidremoveOfflineLicense(byte[] keySetId[])

Removes an offline license.

public booleanrequiresSecureDecoder(byte[] sessionId[], java.lang.String mimeType)

Returns whether the given session requires use of a secure decoder for the given MIME type.

public voidrestoreKeys(byte[] sessionId[], byte[] keySetId[])

Restores persisted offline keys into a session.

public voidsetOnEventListener(ExoMediaDrm.OnEventListener listener)

Sets the listener for DRM events.

public voidsetOnExpirationUpdateListener(ExoMediaDrm.OnExpirationUpdateListener listener)

Sets the listener for session expiration events.

public voidsetOnKeyStatusChangeListener(ExoMediaDrm.OnKeyStatusChangeListener listener)

Sets the listener for key status change events.

public voidsetPlayerIdForSession(byte[] sessionId[], PlayerId playerId)

Sets the PlayerId of the player using a session.

public voidsetPropertyByteArray(java.lang.String propertyName, byte[] value[])

Sets the value of a byte array property.

public voidsetPropertyString(java.lang.String propertyName, java.lang.String value)

Sets the value of a string property.

Fields

public static final int EVENT_KEY_REQUIRED

Event indicating that keys need to be requested from the license server.

public static final int EVENT_KEY_EXPIRED

Event indicating that keys have expired, and are no longer usable.

public static final int EVENT_PROVISION_REQUIRED

Event indicating that a certificate needs to be requested from the provisioning server.

public static final int KEY_TYPE_STREAMING

Key request type for keys that will be used for online use. Streaming keys will not be saved to the device for subsequent use when the device is not connected to a network.

public static final int KEY_TYPE_OFFLINE

Key request type for keys that will be used for offline use. They will be saved to the device for subsequent use when the device is not connected to a network.

public static final int KEY_TYPE_RELEASE

Key request type indicating that saved offline keys should be released.

Methods

public void setOnEventListener(ExoMediaDrm.OnEventListener listener)

Sets the listener for DRM events.

This is an optional method, and some implementations may only support it on certain Android API levels.

Parameters:

listener: The listener to receive events, or null to stop receiving events.

See also: MediaDrm

public void setOnKeyStatusChangeListener(ExoMediaDrm.OnKeyStatusChangeListener listener)

Sets the listener for key status change events.

This is an optional method, and some implementations may only support it on certain Android API levels.

Parameters:

listener: The listener to receive events, or null to stop receiving events.

See also: MediaDrm

public void setOnExpirationUpdateListener(ExoMediaDrm.OnExpirationUpdateListener listener)

Sets the listener for session expiration events.

This is an optional method, and some implementations may only support it on certain Android API levels.

Parameters:

listener: The listener to receive events, or null to stop receiving events.

See also: MediaDrm

public byte[] openSession()

Opens a new DRM session. A session ID is returned.

Returns:

The session ID.

public void closeSession(byte[] sessionId[])

Closes a DRM session.

Parameters:

sessionId: The ID of the session to close.

public void setPlayerIdForSession(byte[] sessionId[], PlayerId playerId)

Sets the PlayerId of the player using a session.

Parameters:

sessionId: The ID of the session.
playerId: The PlayerId of the player using the session.

public ExoMediaDrm.KeyRequest getKeyRequest(byte[] scope[], java.util.List<DrmInitData.SchemeData> schemeDatas, int keyType, java.util.HashMap<java.lang.String, java.lang.String> optionalParameters)

Generates a key request.

Parameters:

scope: If keyType is ExoMediaDrm.KEY_TYPE_STREAMING or ExoMediaDrm.KEY_TYPE_OFFLINE, the ID of the session that the keys will be provided to. If keyType is ExoMediaDrm.KEY_TYPE_RELEASE, the keySetId of the keys to release.
schemeDatas: If key type is ExoMediaDrm.KEY_TYPE_STREAMING or ExoMediaDrm.KEY_TYPE_OFFLINE, a list of DrmInitData.SchemeData instances extracted from the media. Null otherwise.
keyType: The type of the request. Either ExoMediaDrm.KEY_TYPE_STREAMING to acquire keys for streaming, ExoMediaDrm.KEY_TYPE_OFFLINE to acquire keys for offline usage, or ExoMediaDrm.KEY_TYPE_RELEASE to release acquired keys. Releasing keys invalidates them for all sessions.
optionalParameters: Are included in the key request message to allow a client application to provide additional message parameters to the server. This may be null if no additional parameters are to be sent.

Returns:

The generated key request.

See also: MediaDrm

public byte[] provideKeyResponse(byte[] scope[], byte[] response[])

Provides a key response for the last request to be generated using ExoMediaDrm.getKeyRequest(byte[], List, int, HashMap).

Parameters:

scope: If the request had type ExoMediaDrm.KEY_TYPE_STREAMING or ExoMediaDrm.KEY_TYPE_OFFLINE, the ID of the session to provide the keys to. If keyType is ExoMediaDrm.KEY_TYPE_RELEASE, the keySetId of the keys being released.
response: The response data from the server.

Returns:

If the request had type ExoMediaDrm.KEY_TYPE_OFFLINE, the keySetId for the offline keys. An empty byte array or null may be returned for other cases.

public ExoMediaDrm.ProvisionRequest getProvisionRequest()

Generates a provisioning request.

Returns:

The generated provisioning request.

public void provideProvisionResponse(byte[] response[])

Provides a provisioning response for the last request to be generated using ExoMediaDrm.getProvisionRequest().

Parameters:

response: The response data from the server.

public java.util.Map<java.lang.String, java.lang.String> queryKeyStatus(byte[] sessionId[])

Returns the key status for a given session, as {name, value} pairs. Since DRM license policies vary by vendor, the returned entries depend on the DRM plugin being used. Refer to your DRM provider's documentation for more information.

Parameters:

sessionId: The ID of the session being queried.

Returns:

The key status for the session.

public boolean requiresSecureDecoder(byte[] sessionId[], java.lang.String mimeType)

Returns whether the given session requires use of a secure decoder for the given MIME type. Assumes a license policy that requires the highest level of security supported by the session.

Parameters:

sessionId: The ID of the session.
mimeType: The content MIME type to query.

public void acquire()

Increments the reference count. When the caller no longer needs to use the instance, it must call ExoMediaDrm.release() to decrement the reference count.

A new instance will have an initial reference count of 1, and therefore it is not normally necessary for application code to call this method.

public void release()

Decrements the reference count. If the reference count drops to 0 underlying resources are released, and the instance cannot be re-used.

public void restoreKeys(byte[] sessionId[], byte[] keySetId[])

Restores persisted offline keys into a session.

Parameters:

sessionId: The ID of the session into which the keys will be restored.
keySetId: The keySetId of the keys to restore, as provided by the call to ExoMediaDrm.provideKeyResponse(byte[], byte[]) that persisted them.

public void removeOfflineLicense(byte[] keySetId[])

Removes an offline license.

This method is generally not needed, and should only be used if the preferred approach of generating a license release request by passing ExoMediaDrm.KEY_TYPE_RELEASE to ExoMediaDrm.getKeyRequest(byte[], List, int, HashMap) is not possible.

This is an optional method, and some implementations may only support it on certain Android API levels.

See MediaDrm for more details.

Parameters:

keySetId: The keySetId of the license to remove.

public java.util.List<UnknownReference> getOfflineLicenseKeySetIds()

Returns a list of the keySetIds for all offline licenses.

This is an optional method, and some implementations may only support it on certain Android API levels.

See MediaDrm for more details.

Returns:

The list of keySetIds for all offline licenses.

public PersistableBundle getMetrics()

Returns metrics data for this ExoMediaDrm instance, or null if metrics are unavailable.

public java.lang.String getPropertyString(java.lang.String propertyName)

Returns the value of a string property. For standard property names, see MediaDrm.

Parameters:

propertyName: The property name.

Returns:

The property value.

public byte[] getPropertyByteArray(java.lang.String propertyName)

Returns the value of a byte array property. For standard property names, see MediaDrm.

Parameters:

propertyName: The property name.

Returns:

The property value.

public void setPropertyString(java.lang.String propertyName, java.lang.String value)

Sets the value of a string property.

Parameters:

propertyName: The property name.
value: The value.

public void setPropertyByteArray(java.lang.String propertyName, byte[] value[])

Sets the value of a byte array property.

Parameters:

propertyName: The property name.
value: The value.

public CryptoConfig createCryptoConfig(byte[] sessionId[])

Creates a CryptoConfig that can be passed to a compatible decoder to allow decryption of protected content using the specified session.

Parameters:

sessionId: The ID of the session.

Returns:

A CryptoConfig for the given session.

public int getCryptoType()

Returns the of CryptoConfig instances returned by ExoMediaDrm.createCryptoConfig(byte[]).

Source

/*
 * 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 static java.lang.annotation.ElementType.TYPE_USE;

import android.media.DeniedByServerException;
import android.media.MediaCryptoException;
import android.media.MediaDrm;
import android.media.MediaDrmException;
import android.media.NotProvisionedException;
import android.media.ResourceBusyException;
import android.os.Handler;
import android.os.PersistableBundle;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import androidx.media3.common.C;
import androidx.media3.common.DrmInitData.SchemeData;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.decoder.CryptoConfig;
import androidx.media3.exoplayer.analytics.PlayerId;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * Used to obtain keys for decrypting protected media streams.
 *
 * <h2>Reference counting</h2>
 *
 * <p>Access to an instance is managed by reference counting, where {@link #acquire()} increments
 * the reference count and {@link #release()} decrements it. When the reference count drops to 0
 * underlying resources are released, and the instance cannot be re-used.
 *
 * <p>Each new instance has an initial reference count of 1. Hence application code that creates a
 * new instance does not normally need to call {@link #acquire()}, and must call {@link #release()}
 * when the instance is no longer required.
 *
 * @see MediaDrm
 */
@UnstableApi
public interface ExoMediaDrm {

  /** Provider for {@link ExoMediaDrm} instances. */
  interface Provider {

    /**
     * Returns an {@link ExoMediaDrm} instance with an incremented reference count. When the caller
     * no longer needs the instance, it must call {@link ExoMediaDrm#release()} to decrement the
     * reference count.
     */
    ExoMediaDrm acquireExoMediaDrm(UUID uuid);
  }

  /**
   * Provides an {@link ExoMediaDrm} instance owned by the app.
   *
   * <p>Note that when using this provider the app will have instantiated the {@link ExoMediaDrm}
   * instance, and remains responsible for calling {@link ExoMediaDrm#release()} on the instance
   * when it's no longer being used.
   */
  final class AppManagedProvider implements Provider {

    private final ExoMediaDrm exoMediaDrm;

    /** Creates an instance that provides the given {@link ExoMediaDrm}. */
    public AppManagedProvider(ExoMediaDrm exoMediaDrm) {
      this.exoMediaDrm = exoMediaDrm;
    }

    @Override
    public ExoMediaDrm acquireExoMediaDrm(UUID uuid) {
      exoMediaDrm.acquire();
      return exoMediaDrm;
    }
  }

  /** Event indicating that keys need to be requested from the license server. */
  @UnstableApi
  @SuppressWarnings("InlinedApi")
  int EVENT_KEY_REQUIRED = MediaDrm.EVENT_KEY_REQUIRED;

  /** Event indicating that keys have expired, and are no longer usable. */
  @UnstableApi
  @SuppressWarnings("InlinedApi")
  int EVENT_KEY_EXPIRED = MediaDrm.EVENT_KEY_EXPIRED;

  /** Event indicating that a certificate needs to be requested from the provisioning server. */
  @UnstableApi
  @SuppressWarnings("InlinedApi")
  int EVENT_PROVISION_REQUIRED = MediaDrm.EVENT_PROVISION_REQUIRED;

  /**
   * Key request type for keys that will be used for online use. Streaming keys will not be saved to
   * the device for subsequent use when the device is not connected to a network.
   */
  @UnstableApi
  @SuppressWarnings("InlinedApi")
  int KEY_TYPE_STREAMING = MediaDrm.KEY_TYPE_STREAMING;

  /**
   * Key request type for keys that will be used for offline use. They will be saved to the device
   * for subsequent use when the device is not connected to a network.
   */
  @UnstableApi
  @SuppressWarnings("InlinedApi")
  int KEY_TYPE_OFFLINE = MediaDrm.KEY_TYPE_OFFLINE;

  /** Key request type indicating that saved offline keys should be released. */
  @UnstableApi
  @SuppressWarnings("InlinedApi")
  int KEY_TYPE_RELEASE = MediaDrm.KEY_TYPE_RELEASE;

  /**
   * Called when a DRM event occurs.
   *
   * @see MediaDrm.OnEventListener
   */
  interface OnEventListener {
    /**
     * Called when an event occurs that requires the app to be notified
     *
     * @param mediaDrm The {@link ExoMediaDrm} object on which the event occurred.
     * @param sessionId The DRM session ID on which the event occurred.
     * @param event Indicates the event type.
     * @param extra A secondary error code.
     * @param data Optional byte array of data that may be associated with the event.
     */
    void onEvent(
        ExoMediaDrm mediaDrm,
        @Nullable byte[] sessionId,
        int event,
        int extra,
        @Nullable byte[] data);
  }

  /**
   * Called when the keys in a DRM session change state.
   *
   * @see MediaDrm.OnKeyStatusChangeListener
   */
  interface OnKeyStatusChangeListener {
    /**
     * Called when the keys in a session change status, such as when the license is renewed or
     * expires.
     *
     * @param mediaDrm The {@link ExoMediaDrm} object on which the event occurred.
     * @param sessionId The DRM session ID on which the event occurred.
     * @param exoKeyInformation A list of {@link KeyStatus} that contains key ID and status.
     * @param hasNewUsableKey Whether a new key became usable.
     */
    void onKeyStatusChange(
        ExoMediaDrm mediaDrm,
        byte[] sessionId,
        List<KeyStatus> exoKeyInformation,
        boolean hasNewUsableKey);
  }

  /**
   * Called when a session expiration update occurs.
   *
   * @see MediaDrm.OnExpirationUpdateListener
   */
  interface OnExpirationUpdateListener {

    /**
     * Called when a session expiration update occurs, to inform the app about the change in
     * expiration time.
     *
     * @param mediaDrm The {@link ExoMediaDrm} object on which the event occurred.
     * @param sessionId The DRM session ID on which the event occurred
     * @param expirationTimeMs The new expiration time for the keys in the session. The time is in
     *     milliseconds, relative to the Unix epoch. A time of 0 indicates that the keys never
     *     expire.
     */
    void onExpirationUpdate(ExoMediaDrm mediaDrm, byte[] sessionId, long expirationTimeMs);
  }

  /**
   * Defines the status of a key.
   *
   * @see MediaDrm.KeyStatus
   */
  final class KeyStatus {

    private final int statusCode;
    private final byte[] keyId;

    /**
     * Creates an instance.
     *
     * @param statusCode The status code of the key, as defined by {@link
     *     MediaDrm.KeyStatus#getStatusCode()}.
     * @param keyId The ID of the key.
     */
    public KeyStatus(int statusCode, byte[] keyId) {
      this.statusCode = statusCode;
      this.keyId = keyId;
    }

    /** Returns the status of the key, as defined by {@link MediaDrm.KeyStatus#getStatusCode()}. */
    public int getStatusCode() {
      return statusCode;
    }

    /** Returns the ID of the key. */
    public byte[] getKeyId() {
      return keyId;
    }
  }

  /**
   * Contains data used to request keys from a license server.
   *
   * @see MediaDrm.KeyRequest
   */
  final class KeyRequest {

    /**
     * Key request types. One of {@link #REQUEST_TYPE_UNKNOWN}, {@link #REQUEST_TYPE_INITIAL},
     * {@link #REQUEST_TYPE_RENEWAL}, {@link #REQUEST_TYPE_RELEASE}, {@link #REQUEST_TYPE_NONE} or
     * {@link #REQUEST_TYPE_UPDATE}.
     */
    @Documented
    @Retention(RetentionPolicy.SOURCE)
    @Target(TYPE_USE)
    @IntDef({
      REQUEST_TYPE_UNKNOWN,
      REQUEST_TYPE_INITIAL,
      REQUEST_TYPE_RENEWAL,
      REQUEST_TYPE_RELEASE,
      REQUEST_TYPE_NONE,
      REQUEST_TYPE_UPDATE,
    })
    public @interface RequestType {}

    /**
     * Value returned from {@link #getRequestType()} if the underlying key request does not specify
     * a type.
     */
    public static final int REQUEST_TYPE_UNKNOWN = Integer.MIN_VALUE;

    /** Key request type for an initial license request. */
    public static final int REQUEST_TYPE_INITIAL = MediaDrm.KeyRequest.REQUEST_TYPE_INITIAL;

    /** Key request type for license renewal. */
    public static final int REQUEST_TYPE_RENEWAL = MediaDrm.KeyRequest.REQUEST_TYPE_RENEWAL;

    /** Key request type for license release. */
    public static final int REQUEST_TYPE_RELEASE = MediaDrm.KeyRequest.REQUEST_TYPE_RELEASE;

    /**
     * Key request type if keys are already loaded and available for use. No license request is
     * necessary, and no key request data is returned.
     */
    public static final int REQUEST_TYPE_NONE = MediaDrm.KeyRequest.REQUEST_TYPE_NONE;

    /**
     * Key request type if keys have been loaded, but an additional license request is needed to
     * update their values.
     */
    public static final int REQUEST_TYPE_UPDATE = MediaDrm.KeyRequest.REQUEST_TYPE_UPDATE;

    private final byte[] data;
    private final String licenseServerUrl;
    private final @RequestType int requestType;

    /**
     * Creates an instance with {@link #REQUEST_TYPE_UNKNOWN}.
     *
     * @param data The opaque key request data.
     * @param licenseServerUrl The license server URL to which the request should be made.
     */
    public KeyRequest(byte[] data, String licenseServerUrl) {
      this(data, licenseServerUrl, REQUEST_TYPE_UNKNOWN);
    }

    /**
     * Creates an instance.
     *
     * @param data The opaque key request data.
     * @param licenseServerUrl The license server URL to which the request should be made.
     * @param requestType The type of the request, or {@link #REQUEST_TYPE_UNKNOWN}.
     */
    public KeyRequest(byte[] data, String licenseServerUrl, @RequestType int requestType) {
      this.data = data;
      this.licenseServerUrl = licenseServerUrl;
      this.requestType = requestType;
    }

    /** Returns the opaque key request data. */
    public byte[] getData() {
      return data;
    }

    /** Returns the URL of the license server to which the request should be made. */
    public String getLicenseServerUrl() {
      return licenseServerUrl;
    }

    /**
     * Returns the type of the request, or {@link #REQUEST_TYPE_UNKNOWN} if the underlying key
     * request does not specify a type. Note that when using a platform {@link MediaDrm} instance,
     * key requests only specify a type on API levels 23 and above.
     */
    public @RequestType int getRequestType() {
      return requestType;
    }
  }

  /**
   * Contains data to request a certificate from a provisioning server.
   *
   * @see MediaDrm.ProvisionRequest
   */
  final class ProvisionRequest {

    private final byte[] data;
    private final String defaultUrl;

    /**
     * Creates an instance.
     *
     * @param data The opaque provisioning request data.
     * @param defaultUrl The default URL of the provisioning server to which the request can be
     *     made, or the empty string if not known.
     */
    public ProvisionRequest(byte[] data, String defaultUrl) {
      this.data = data;
      this.defaultUrl = defaultUrl;
    }

    /** Returns the opaque provisioning request data. */
    public byte[] getData() {
      return data;
    }

    /**
     * Returns the default URL of the provisioning server to which the request can be made, or the
     * empty string if not known.
     */
    public String getDefaultUrl() {
      return defaultUrl;
    }
  }

  /**
   * Sets the listener for DRM events.
   *
   * <p>This is an optional method, and some implementations may only support it on certain Android
   * API levels.
   *
   * @param listener The listener to receive events, or {@code null} to stop receiving events.
   * @throws UnsupportedOperationException if the implementation doesn't support this method.
   * @see MediaDrm#setOnEventListener(MediaDrm.OnEventListener)
   */
  void setOnEventListener(@Nullable OnEventListener listener);

  /**
   * Sets the listener for key status change events.
   *
   * <p>This is an optional method, and some implementations may only support it on certain Android
   * API levels.
   *
   * @param listener The listener to receive events, or {@code null} to stop receiving events.
   * @throws UnsupportedOperationException if the implementation doesn't support this method.
   * @see MediaDrm#setOnKeyStatusChangeListener(MediaDrm.OnKeyStatusChangeListener, Handler)
   */
  void setOnKeyStatusChangeListener(@Nullable OnKeyStatusChangeListener listener);

  /**
   * Sets the listener for session expiration events.
   *
   * <p>This is an optional method, and some implementations may only support it on certain Android
   * API levels.
   *
   * @param listener The listener to receive events, or {@code null} to stop receiving events.
   * @throws UnsupportedOperationException if the implementation doesn't support this method.
   * @see MediaDrm#setOnExpirationUpdateListener(MediaDrm.OnExpirationUpdateListener, Handler)
   */
  void setOnExpirationUpdateListener(@Nullable OnExpirationUpdateListener listener);

  /**
   * Opens a new DRM session. A session ID is returned.
   *
   * @return The session ID.
   * @throws NotProvisionedException If provisioning is needed.
   * @throws ResourceBusyException If required resources are in use.
   * @throws MediaDrmException If the session could not be opened.
   */
  byte[] openSession() throws MediaDrmException;

  /**
   * Closes a DRM session.
   *
   * @param sessionId The ID of the session to close.
   */
  void closeSession(byte[] sessionId);

  /**
   * Sets the {@link PlayerId} of the player using a session.
   *
   * @param sessionId The ID of the session.
   * @param playerId The {@link PlayerId} of the player using the session.
   */
  default void setPlayerIdForSession(byte[] sessionId, PlayerId playerId) {}

  /**
   * Generates a key request.
   *
   * @param scope If {@code keyType} is {@link #KEY_TYPE_STREAMING} or {@link #KEY_TYPE_OFFLINE},
   *     the ID of the session that the keys will be provided to. If {@code keyType} is {@link
   *     #KEY_TYPE_RELEASE}, the {@code keySetId} of the keys to release.
   * @param schemeDatas If key type is {@link #KEY_TYPE_STREAMING} or {@link #KEY_TYPE_OFFLINE}, a
   *     list of {@link SchemeData} instances extracted from the media. Null otherwise.
   * @param keyType The type of the request. Either {@link #KEY_TYPE_STREAMING} to acquire keys for
   *     streaming, {@link #KEY_TYPE_OFFLINE} to acquire keys for offline usage, or {@link
   *     #KEY_TYPE_RELEASE} to release acquired keys. Releasing keys invalidates them for all
   *     sessions.
   * @param optionalParameters Are included in the key request message to allow a client application
   *     to provide additional message parameters to the server. This may be {@code null} if no
   *     additional parameters are to be sent.
   * @return The generated key request.
   * @see MediaDrm#getKeyRequest(byte[], byte[], String, int, HashMap)
   */
  KeyRequest getKeyRequest(
      byte[] scope,
      @Nullable List<SchemeData> schemeDatas,
      int keyType,
      @Nullable HashMap<String, String> optionalParameters)
      throws NotProvisionedException;

  /**
   * Provides a key response for the last request to be generated using {@link #getKeyRequest}.
   *
   * @param scope If the request had type {@link #KEY_TYPE_STREAMING} or {@link #KEY_TYPE_OFFLINE},
   *     the ID of the session to provide the keys to. If {@code keyType} is {@link
   *     #KEY_TYPE_RELEASE}, the {@code keySetId} of the keys being released.
   * @param response The response data from the server.
   * @return If the request had type {@link #KEY_TYPE_OFFLINE}, the {@code keySetId} for the offline
   *     keys. An empty byte array or {@code null} may be returned for other cases.
   * @throws NotProvisionedException If the response indicates that provisioning is needed.
   * @throws DeniedByServerException If the response indicates that the server rejected the request.
   */
  @Nullable
  byte[] provideKeyResponse(byte[] scope, byte[] response)
      throws NotProvisionedException, DeniedByServerException;

  /**
   * Generates a provisioning request.
   *
   * @return The generated provisioning request.
   */
  ProvisionRequest getProvisionRequest();

  /**
   * Provides a provisioning response for the last request to be generated using {@link
   * #getProvisionRequest()}.
   *
   * @param response The response data from the server.
   * @throws DeniedByServerException If the response indicates that the server rejected the request.
   */
  void provideProvisionResponse(byte[] response) throws DeniedByServerException;

  /**
   * Returns the key status for a given session, as {name, value} pairs. Since DRM license policies
   * vary by vendor, the returned entries depend on the DRM plugin being used. Refer to your DRM
   * provider's documentation for more information.
   *
   * @param sessionId The ID of the session being queried.
   * @return The key status for the session.
   */
  Map<String, String> queryKeyStatus(byte[] sessionId);

  /**
   * Returns whether the given session requires use of a secure decoder for the given MIME type.
   * Assumes a license policy that requires the highest level of security supported by the session.
   *
   * @param sessionId The ID of the session.
   * @param mimeType The content MIME type to query.
   */
  boolean requiresSecureDecoder(byte[] sessionId, String mimeType);

  /**
   * Increments the reference count. When the caller no longer needs to use the instance, it must
   * call {@link #release()} to decrement the reference count.
   *
   * <p>A new instance will have an initial reference count of 1, and therefore it is not normally
   * necessary for application code to call this method.
   */
  void acquire();

  /**
   * Decrements the reference count. If the reference count drops to 0 underlying resources are
   * released, and the instance cannot be re-used.
   */
  void release();

  /**
   * Restores persisted offline keys into a session.
   *
   * @param sessionId The ID of the session into which the keys will be restored.
   * @param keySetId The {@code keySetId} of the keys to restore, as provided by the call to {@link
   *     #provideKeyResponse} that persisted them.
   */
  void restoreKeys(byte[] sessionId, byte[] keySetId);

  /**
   * Removes an offline license.
   *
   * <p>This method is generally not needed, and should only be used if the preferred approach of
   * generating a license release request by passing {@link #KEY_TYPE_RELEASE} to {@link
   * #getKeyRequest} is not possible.
   *
   * <p>This is an optional method, and some implementations may only support it on certain Android
   * API levels.
   *
   * <p>See {@link MediaDrm#removeOfflineLicense(byte[])} for more details.
   *
   * @param keySetId The {@code keySetId} of the license to remove.
   * @throws UnsupportedOperationException if the implementation doesn't support this method.
   */
  default void removeOfflineLicense(byte[] keySetId) {
    throw new UnsupportedOperationException();
  }

  /**
   * Returns a list of the {@code keySetIds} for all offline licenses.
   *
   * <p>This is an optional method, and some implementations may only support it on certain Android
   * API levels.
   *
   * <p>See {@link MediaDrm#getOfflineLicenseKeySetIds()} for more details.
   *
   * @return The list of {@code keySetIds} for all offline licenses.
   * @throws UnsupportedOperationException if the implementation doesn't support this method.
   */
  default List<byte[]> getOfflineLicenseKeySetIds() {
    throw new UnsupportedOperationException();
  }

  /**
   * Returns metrics data for this ExoMediaDrm instance, or {@code null} if metrics are unavailable.
   */
  @Nullable
  PersistableBundle getMetrics();

  /**
   * Returns the value of a string property. For standard property names, see {@link
   * MediaDrm#getPropertyString}.
   *
   * @param propertyName The property name.
   * @return The property value.
   * @throws IllegalArgumentException If the underlying DRM plugin does not support the property.
   */
  String getPropertyString(String propertyName);

  /**
   * Returns the value of a byte array property. For standard property names, see {@link
   * MediaDrm#getPropertyByteArray}.
   *
   * @param propertyName The property name.
   * @return The property value.
   * @throws IllegalArgumentException If the underlying DRM plugin does not support the property.
   */
  byte[] getPropertyByteArray(String propertyName);

  /**
   * Sets the value of a string property.
   *
   * @param propertyName The property name.
   * @param value The value.
   * @throws IllegalArgumentException If the underlying DRM plugin does not support the property.
   */
  void setPropertyString(String propertyName, String value);

  /**
   * Sets the value of a byte array property.
   *
   * @param propertyName The property name.
   * @param value The value.
   * @throws IllegalArgumentException If the underlying DRM plugin does not support the property.
   */
  void setPropertyByteArray(String propertyName, byte[] value);

  /**
   * Creates a {@link CryptoConfig} that can be passed to a compatible decoder to allow decryption
   * of protected content using the specified session.
   *
   * @param sessionId The ID of the session.
   * @return A {@link CryptoConfig} for the given session.
   * @throws MediaCryptoException If a {@link CryptoConfig} could not be created.
   */
  CryptoConfig createCryptoConfig(byte[] sessionId) throws MediaCryptoException;

  /**
   * Returns the {@link C.CryptoType type} of {@link CryptoConfig} instances returned by {@link
   * #createCryptoConfig}.
   */
  @C.CryptoType
  int getCryptoType();
}