diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 2181154745a..c086f9bc6d4 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -33,6 +33,7 @@ * Add release method to Cache interface. * Prevent multiple instances of SimpleCache in the same folder. Previous instance must be released. +* DRM: Allow multiple listeners for `DefaultDrmSessionManager`. * Fix ANR issue on Redmi 4X and Redmi Note 4 ([#4006](https://github.com/google/ExoPlayer/issues/4006)). * Removed default renderer time offset of 60000000 from internal player. The diff --git a/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java b/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java index e251a760a42..f625f71f69e 100644 --- a/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java +++ b/demos/main/src/main/java/com/google/android/exoplayer2/demo/PlayerActivity.java @@ -432,8 +432,11 @@ private DrmSessionManager buildDrmSessionManagerV18(UUID u keyRequestPropertiesArray[i + 1]); } } - return new DefaultDrmSessionManager<>(uuid, FrameworkMediaDrm.newInstance(uuid), drmCallback, - null, mainHandler, eventLogger, multiSession); + DefaultDrmSessionManager drmSessionManager = + new DefaultDrmSessionManager<>( + uuid, FrameworkMediaDrm.newInstance(uuid), drmCallback, null, multiSession); + drmSessionManager.addListener(mainHandler, eventLogger); + return drmSessionManager; } private void releasePlayer() { diff --git a/library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSession.java b/library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSession.java index 25fdaba5b84..c57b0231393 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSession.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSession.java @@ -25,6 +25,7 @@ import android.util.Log; import android.util.Pair; import com.google.android.exoplayer2.C; +import com.google.android.exoplayer2.drm.DefaultDrmSessionEventListener.EventDispatcher; import com.google.android.exoplayer2.drm.ExoMediaDrm.DefaultKeyRequest; import com.google.android.exoplayer2.drm.ExoMediaDrm.KeyRequest; import com.google.android.exoplayer2.drm.ExoMediaDrm.ProvisionRequest; @@ -80,8 +81,7 @@ public interface ProvisioningManager { private final String mimeType; private final @DefaultDrmSessionManager.Mode int mode; private final HashMap optionalKeyRequestParameters; - private final Handler eventHandler; - private final DefaultDrmSessionManager.EventListener eventListener; + private final EventDispatcher eventDispatcher; private final int initialDrmRequestRetryCount; /* package */ final MediaDrmCallback callback; @@ -109,17 +109,22 @@ public interface ProvisioningManager { * @param optionalKeyRequestParameters The optional key request parameters. * @param callback The media DRM callback. * @param playbackLooper The playback looper. - * @param eventHandler The handler to post listener events. - * @param eventListener The DRM session manager event listener. + * @param eventDispatcher The dispatcher for DRM session manager events. * @param initialDrmRequestRetryCount The number of times to retry for initial provisioning and * key request before reporting error. */ - public DefaultDrmSession(UUID uuid, ExoMediaDrm mediaDrm, - ProvisioningManager provisioningManager, byte[] initData, String mimeType, - @DefaultDrmSessionManager.Mode int mode, byte[] offlineLicenseKeySetId, - HashMap optionalKeyRequestParameters, MediaDrmCallback callback, - Looper playbackLooper, Handler eventHandler, - DefaultDrmSessionManager.EventListener eventListener, + public DefaultDrmSession( + UUID uuid, + ExoMediaDrm mediaDrm, + ProvisioningManager provisioningManager, + byte[] initData, + String mimeType, + @DefaultDrmSessionManager.Mode int mode, + byte[] offlineLicenseKeySetId, + HashMap optionalKeyRequestParameters, + MediaDrmCallback callback, + Looper playbackLooper, + EventDispatcher eventDispatcher, int initialDrmRequestRetryCount) { this.uuid = uuid; this.provisioningManager = provisioningManager; @@ -129,9 +134,7 @@ public DefaultDrmSession(UUID uuid, ExoMediaDrm mediaDrm, this.optionalKeyRequestParameters = optionalKeyRequestParameters; this.callback = callback; this.initialDrmRequestRetryCount = initialDrmRequestRetryCount; - - this.eventHandler = eventHandler; - this.eventListener = eventListener; + this.eventDispatcher = eventDispatcher; state = STATE_OPENING; postResponseHandler = new PostResponseHandler(playbackLooper); @@ -306,14 +309,7 @@ private void doLicense(boolean allowRetry) { onError(new KeysExpiredException()); } else { state = STATE_OPENED_WITH_KEYS; - if (eventHandler != null && eventListener != null) { - eventHandler.post(new Runnable() { - @Override - public void run() { - eventListener.onDrmKeysRestored(); - } - }); - } + eventDispatcher.drmKeysRestored(); } } break; @@ -391,14 +387,7 @@ private void onKeyResponse(Object response) { } if (mode == DefaultDrmSessionManager.MODE_RELEASE) { mediaDrm.provideKeyResponse(offlineLicenseKeySetId, responseData); - if (eventHandler != null && eventListener != null) { - eventHandler.post(new Runnable() { - @Override - public void run() { - eventListener.onDrmKeysRemoved(); - } - }); - } + eventDispatcher.drmKeysRemoved(); } else { byte[] keySetId = mediaDrm.provideKeyResponse(sessionId, responseData); if ((mode == DefaultDrmSessionManager.MODE_DOWNLOAD @@ -407,14 +396,7 @@ public void run() { offlineLicenseKeySetId = keySetId; } state = STATE_OPENED_WITH_KEYS; - if (eventHandler != null && eventListener != null) { - eventHandler.post(new Runnable() { - @Override - public void run() { - eventListener.onDrmKeysLoaded(); - } - }); - } + eventDispatcher.drmKeysLoaded(); } } catch (Exception e) { onKeysError(e); @@ -438,14 +420,7 @@ private void onKeysError(Exception e) { private void onError(final Exception e) { lastException = new DrmSessionException(e); - if (eventHandler != null && eventListener != null) { - eventHandler.post(new Runnable() { - @Override - public void run() { - eventListener.onDrmSessionManagerError(e); - } - }); - } + eventDispatcher.drmSessionManagerError(e); if (state != STATE_OPENED_WITH_KEYS) { state = STATE_ERROR; } diff --git a/library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSessionEventListener.java b/library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSessionEventListener.java new file mode 100644 index 00000000000..8a060c5db79 --- /dev/null +++ b/library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSessionEventListener.java @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2018 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 com.google.android.exoplayer2.drm; + +import android.os.Handler; +import com.google.android.exoplayer2.Player; +import java.util.concurrent.CopyOnWriteArrayList; + +/** Listener of {@link DefaultDrmSessionManager} events. */ +public interface DefaultDrmSessionEventListener { + + /** Called each time keys are loaded. */ + void onDrmKeysLoaded(); + + /** + * Called when a drm error occurs. + * + *

This method being called does not indicate that playback has failed, or that it will fail. + * The player may be able to recover from the error and continue. Hence applications should + * not implement this method to display a user visible error or initiate an application + * level retry ({@link Player.EventListener#onPlayerError} is the appropriate place to implement + * such behavior). This method is called to provide the application with an opportunity to log the + * error if it wishes to do so. + * + * @param error The corresponding exception. + */ + void onDrmSessionManagerError(Exception error); + + /** Called each time offline keys are restored. */ + void onDrmKeysRestored(); + + /** Called each time offline keys are removed. */ + void onDrmKeysRemoved(); + + /** Dispatches drm events to all registered listeners. */ + final class EventDispatcher { + + private final CopyOnWriteArrayList listeners; + + /** Creates event dispatcher. */ + public EventDispatcher() { + listeners = new CopyOnWriteArrayList<>(); + } + + /** Adds listener to event dispatcher. */ + public void addListener(Handler handler, DefaultDrmSessionEventListener eventListener) { + listeners.add(new HandlerAndListener(handler, eventListener)); + } + + /** Removes listener from event dispatcher. */ + public void removeListener(DefaultDrmSessionEventListener eventListener) { + for (HandlerAndListener handlerAndListener : listeners) { + if (handlerAndListener.listener == eventListener) { + listeners.remove(handlerAndListener); + } + } + } + + /** Dispatches {@link DefaultDrmSessionEventListener#onDrmKeysLoaded()}. */ + public void drmKeysLoaded() { + for (HandlerAndListener handlerAndListener : listeners) { + final DefaultDrmSessionEventListener listener = handlerAndListener.listener; + handlerAndListener.handler.post( + new Runnable() { + @Override + public void run() { + listener.onDrmKeysLoaded(); + } + }); + } + } + + /** Dispatches {@link DefaultDrmSessionEventListener#onDrmSessionManagerError(Exception)}. */ + public void drmSessionManagerError(final Exception e) { + for (HandlerAndListener handlerAndListener : listeners) { + final DefaultDrmSessionEventListener listener = handlerAndListener.listener; + handlerAndListener.handler.post( + new Runnable() { + @Override + public void run() { + listener.onDrmSessionManagerError(e); + } + }); + } + } + + /** Dispatches {@link DefaultDrmSessionEventListener#onDrmKeysRestored()}. */ + public void drmKeysRestored() { + for (HandlerAndListener handlerAndListener : listeners) { + final DefaultDrmSessionEventListener listener = handlerAndListener.listener; + handlerAndListener.handler.post( + new Runnable() { + @Override + public void run() { + listener.onDrmKeysRestored(); + } + }); + } + } + + /** Dispatches {@link DefaultDrmSessionEventListener#onDrmKeysRemoved()}. */ + public void drmKeysRemoved() { + for (HandlerAndListener handlerAndListener : listeners) { + final DefaultDrmSessionEventListener listener = handlerAndListener.listener; + handlerAndListener.handler.post( + new Runnable() { + @Override + public void run() { + listener.onDrmKeysRemoved(); + } + }); + } + } + + private static final class HandlerAndListener { + + public final Handler handler; + public final DefaultDrmSessionEventListener listener; + + public HandlerAndListener(Handler handler, DefaultDrmSessionEventListener eventListener) { + this.handler = handler; + this.listener = eventListener; + } + } + } +} diff --git a/library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSessionManager.java b/library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSessionManager.java index ca0302cdcad..d5a6f0c36e4 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSessionManager.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/drm/DefaultDrmSessionManager.java @@ -25,8 +25,8 @@ import android.text.TextUtils; import android.util.Log; import com.google.android.exoplayer2.C; -import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.drm.DefaultDrmSession.ProvisioningManager; +import com.google.android.exoplayer2.drm.DefaultDrmSessionEventListener.EventDispatcher; import com.google.android.exoplayer2.drm.DrmInitData.SchemeData; import com.google.android.exoplayer2.drm.DrmSession.DrmSessionException; import com.google.android.exoplayer2.drm.ExoMediaDrm.OnEventListener; @@ -48,41 +48,9 @@ public class DefaultDrmSessionManager implements DrmSessionManager, ProvisioningManager { - /** - * Listener of {@link DefaultDrmSessionManager} events. - */ - public interface EventListener { - - /** - * Called each time keys are loaded. - */ - void onDrmKeysLoaded(); - - /** - * Called when a drm error occurs. - *

- * This method being called does not indicate that playback has failed, or that it will fail. - * The player may be able to recover from the error and continue. Hence applications should - * not implement this method to display a user visible error or initiate an application - * level retry ({@link Player.EventListener#onPlayerError} is the appropriate place to implement - * such behavior). This method is called to provide the application with an opportunity to log - * the error if it wishes to do so. - * - * @param e The corresponding exception. - */ - void onDrmSessionManagerError(Exception e); - - /** - * Called each time offline keys are restored. - */ - void onDrmKeysRestored(); - - /** - * Called each time offline keys are removed. - */ - void onDrmKeysRemoved(); - - } + /** @deprecated Use {@link DefaultDrmSessionEventListener}. */ + @Deprecated + public interface EventListener extends DefaultDrmSessionEventListener {} /** * Signals that the {@link DrmInitData} passed to {@link #acquireSession} does not contain does @@ -127,8 +95,7 @@ private MissingSchemeDataException(UUID uuid) { private final ExoMediaDrm mediaDrm; private final MediaDrmCallback callback; private final HashMap optionalKeyRequestParameters; - private final Handler eventHandler; - private final EventListener eventListener; + private final EventDispatcher eventDispatcher; private final boolean multiSession; private final int initialDrmRequestRetryCount; @@ -141,40 +108,66 @@ private MissingSchemeDataException(UUID uuid) { /* package */ volatile MediaDrmHandler mediaDrmHandler; + /** + * @deprecated Use {@link #newWidevineInstance(MediaDrmCallback, HashMap)} and {@link + * #addListener(Handler, DefaultDrmSessionEventListener)}. + */ + @Deprecated + public static DefaultDrmSessionManager newWidevineInstance( + MediaDrmCallback callback, + HashMap optionalKeyRequestParameters, + Handler eventHandler, + DefaultDrmSessionEventListener eventListener) + throws UnsupportedDrmException { + DefaultDrmSessionManager drmSessionManager = + newWidevineInstance(callback, optionalKeyRequestParameters); + drmSessionManager.addListener(eventHandler, eventListener); + return drmSessionManager; + } + /** * Instantiates a new instance using the Widevine scheme. * * @param callback Performs key and provisioning requests. * @param optionalKeyRequestParameters An optional map of parameters to pass as the last argument * to {@link ExoMediaDrm#getKeyRequest(byte[], byte[], String, int, HashMap)}. May be null. - * @param eventHandler A handler to use when delivering events to {@code eventListener}. May be - * null if delivery of events is not required. - * @param eventListener A listener of events. May be null if delivery of events is not required. * @throws UnsupportedDrmException If the specified DRM scheme is not supported. */ public static DefaultDrmSessionManager newWidevineInstance( - MediaDrmCallback callback, HashMap optionalKeyRequestParameters, - Handler eventHandler, EventListener eventListener) throws UnsupportedDrmException { - return newFrameworkInstance(C.WIDEVINE_UUID, callback, optionalKeyRequestParameters, - eventHandler, eventListener); + MediaDrmCallback callback, HashMap optionalKeyRequestParameters) + throws UnsupportedDrmException { + return newFrameworkInstance(C.WIDEVINE_UUID, callback, optionalKeyRequestParameters); + } + + /** + * @deprecated Use {@link #newPlayReadyInstance(MediaDrmCallback, String)} and {@link + * #addListener(Handler, DefaultDrmSessionEventListener)}. + */ + @Deprecated + public static DefaultDrmSessionManager newPlayReadyInstance( + MediaDrmCallback callback, + String customData, + Handler eventHandler, + DefaultDrmSessionEventListener eventListener) + throws UnsupportedDrmException { + DefaultDrmSessionManager drmSessionManager = + newPlayReadyInstance(callback, customData); + drmSessionManager.addListener(eventHandler, eventListener); + return drmSessionManager; } /** * Instantiates a new instance using the PlayReady scheme. - *

- * Note that PlayReady is unsupported by most Android devices, with the exception of Android TV + * + *

Note that PlayReady is unsupported by most Android devices, with the exception of Android TV * devices, which do provide support. * * @param callback Performs key and provisioning requests. * @param customData Optional custom data to include in requests generated by the instance. - * @param eventHandler A handler to use when delivering events to {@code eventListener}. May be - * null if delivery of events is not required. - * @param eventListener A listener of events. May be null if delivery of events is not required. * @throws UnsupportedDrmException If the specified DRM scheme is not supported. */ public static DefaultDrmSessionManager newPlayReadyInstance( - MediaDrmCallback callback, String customData, Handler eventHandler, - EventListener eventListener) throws UnsupportedDrmException { + MediaDrmCallback callback, String customData) throws UnsupportedDrmException { HashMap optionalKeyRequestParameters; if (!TextUtils.isEmpty(customData)) { optionalKeyRequestParameters = new HashMap<>(); @@ -182,8 +175,25 @@ public static DefaultDrmSessionManager newPlayReadyInstanc } else { optionalKeyRequestParameters = null; } - return newFrameworkInstance(C.PLAYREADY_UUID, callback, optionalKeyRequestParameters, - eventHandler, eventListener); + return newFrameworkInstance(C.PLAYREADY_UUID, callback, optionalKeyRequestParameters); + } + + /** + * @deprecated Use {@link #newFrameworkInstance(UUID, MediaDrmCallback, HashMap)} and {@link + * #addListener(Handler, DefaultDrmSessionEventListener)}. + */ + @Deprecated + public static DefaultDrmSessionManager newFrameworkInstance( + UUID uuid, + MediaDrmCallback callback, + HashMap optionalKeyRequestParameters, + Handler eventHandler, + DefaultDrmSessionEventListener eventListener) + throws UnsupportedDrmException { + DefaultDrmSessionManager drmSessionManager = + newFrameworkInstance(uuid, callback, optionalKeyRequestParameters); + drmSessionManager.addListener(eventHandler, eventListener); + return drmSessionManager; } /** @@ -193,34 +203,72 @@ public static DefaultDrmSessionManager newPlayReadyInstanc * @param callback Performs key and provisioning requests. * @param optionalKeyRequestParameters An optional map of parameters to pass as the last argument * to {@link ExoMediaDrm#getKeyRequest(byte[], byte[], String, int, HashMap)}. May be null. - * @param eventHandler A handler to use when delivering events to {@code eventListener}. May be - * null if delivery of events is not required. - * @param eventListener A listener of events. May be null if delivery of events is not required. * @throws UnsupportedDrmException If the specified DRM scheme is not supported. */ public static DefaultDrmSessionManager newFrameworkInstance( - UUID uuid, MediaDrmCallback callback, HashMap optionalKeyRequestParameters, - Handler eventHandler, EventListener eventListener) throws UnsupportedDrmException { - return new DefaultDrmSessionManager<>(uuid, FrameworkMediaDrm.newInstance(uuid), callback, - optionalKeyRequestParameters, eventHandler, eventListener, false, + UUID uuid, MediaDrmCallback callback, HashMap optionalKeyRequestParameters) + throws UnsupportedDrmException { + return new DefaultDrmSessionManager<>( + uuid, + FrameworkMediaDrm.newInstance(uuid), + callback, + optionalKeyRequestParameters, + /* multiSession= */ false, INITIAL_DRM_REQUEST_RETRY_COUNT); } + /** + * @deprecated Use {@link #DefaultDrmSessionManager(UUID, ExoMediaDrm, MediaDrmCallback, HashMap)} + * and {@link #addListener(Handler, DefaultDrmSessionEventListener)}. + */ + @Deprecated + public DefaultDrmSessionManager( + UUID uuid, + ExoMediaDrm mediaDrm, + MediaDrmCallback callback, + HashMap optionalKeyRequestParameters, + Handler eventHandler, + DefaultDrmSessionEventListener eventListener) { + this(uuid, mediaDrm, callback, optionalKeyRequestParameters); + addListener(eventHandler, eventListener); + } + /** * @param uuid The UUID of the drm scheme. * @param mediaDrm An underlying {@link ExoMediaDrm} for use by the manager. * @param callback Performs key and provisioning requests. * @param optionalKeyRequestParameters An optional map of parameters to pass as the last argument * to {@link ExoMediaDrm#getKeyRequest(byte[], byte[], String, int, HashMap)}. May be null. - * @param eventHandler A handler to use when delivering events to {@code eventListener}. May be - * null if delivery of events is not required. - * @param eventListener A listener of events. May be null if delivery of events is not required. */ - public DefaultDrmSessionManager(UUID uuid, ExoMediaDrm mediaDrm, MediaDrmCallback callback, - HashMap optionalKeyRequestParameters, Handler eventHandler, - EventListener eventListener) { - this(uuid, mediaDrm, callback, optionalKeyRequestParameters, eventHandler, eventListener, - false, INITIAL_DRM_REQUEST_RETRY_COUNT); + public DefaultDrmSessionManager( + UUID uuid, + ExoMediaDrm mediaDrm, + MediaDrmCallback callback, + HashMap optionalKeyRequestParameters) { + this( + uuid, + mediaDrm, + callback, + optionalKeyRequestParameters, + /* multiSession= */ false, + INITIAL_DRM_REQUEST_RETRY_COUNT); + } + + /** + * @deprecated Use {@link #DefaultDrmSessionManager(UUID, ExoMediaDrm, MediaDrmCallback, HashMap, + * boolean)} and {@link #addListener(Handler, DefaultDrmSessionEventListener)}. + */ + @Deprecated + public DefaultDrmSessionManager( + UUID uuid, + ExoMediaDrm mediaDrm, + MediaDrmCallback callback, + HashMap optionalKeyRequestParameters, + Handler eventHandler, + DefaultDrmSessionEventListener eventListener, + boolean multiSession) { + this(uuid, mediaDrm, callback, optionalKeyRequestParameters, multiSession); + addListener(eventHandler, eventListener); } /** @@ -229,17 +277,46 @@ public DefaultDrmSessionManager(UUID uuid, ExoMediaDrm mediaDrm, MediaDrmCall * @param callback Performs key and provisioning requests. * @param optionalKeyRequestParameters An optional map of parameters to pass as the last argument * to {@link ExoMediaDrm#getKeyRequest(byte[], byte[], String, int, HashMap)}. May be null. - * @param eventHandler A handler to use when delivering events to {@code eventListener}. May be - * null if delivery of events is not required. - * @param eventListener A listener of events. May be null if delivery of events is not required. * @param multiSession A boolean that specify whether multiple key session support is enabled. * Default is false. */ - public DefaultDrmSessionManager(UUID uuid, ExoMediaDrm mediaDrm, MediaDrmCallback callback, - HashMap optionalKeyRequestParameters, Handler eventHandler, - EventListener eventListener, boolean multiSession) { - this(uuid, mediaDrm, callback, optionalKeyRequestParameters, eventHandler, eventListener, - multiSession, INITIAL_DRM_REQUEST_RETRY_COUNT); + public DefaultDrmSessionManager( + UUID uuid, + ExoMediaDrm mediaDrm, + MediaDrmCallback callback, + HashMap optionalKeyRequestParameters, + boolean multiSession) { + this( + uuid, + mediaDrm, + callback, + optionalKeyRequestParameters, + multiSession, + INITIAL_DRM_REQUEST_RETRY_COUNT); + } + + /** + * @deprecated Use {@link #DefaultDrmSessionManager(UUID, ExoMediaDrm, MediaDrmCallback, HashMap, + * boolean, int)} and {@link #addListener(Handler, DefaultDrmSessionEventListener)}. + */ + @Deprecated + public DefaultDrmSessionManager( + UUID uuid, + ExoMediaDrm mediaDrm, + MediaDrmCallback callback, + HashMap optionalKeyRequestParameters, + Handler eventHandler, + DefaultDrmSessionEventListener eventListener, + boolean multiSession, + int initialDrmRequestRetryCount) { + this( + uuid, + mediaDrm, + callback, + optionalKeyRequestParameters, + multiSession, + initialDrmRequestRetryCount); + addListener(eventHandler, eventListener); } /** @@ -248,17 +325,18 @@ public DefaultDrmSessionManager(UUID uuid, ExoMediaDrm mediaDrm, MediaDrmCall * @param callback Performs key and provisioning requests. * @param optionalKeyRequestParameters An optional map of parameters to pass as the last argument * to {@link ExoMediaDrm#getKeyRequest(byte[], byte[], String, int, HashMap)}. May be null. - * @param eventHandler A handler to use when delivering events to {@code eventListener}. May be - * null if delivery of events is not required. - * @param eventListener A listener of events. May be null if delivery of events is not required. * @param multiSession A boolean that specify whether multiple key session support is enabled. * Default is false. * @param initialDrmRequestRetryCount The number of times to retry for initial provisioning and * key request before reporting error. */ - public DefaultDrmSessionManager(UUID uuid, ExoMediaDrm mediaDrm, MediaDrmCallback callback, - HashMap optionalKeyRequestParameters, Handler eventHandler, - EventListener eventListener, boolean multiSession, int initialDrmRequestRetryCount) { + public DefaultDrmSessionManager( + UUID uuid, + ExoMediaDrm mediaDrm, + MediaDrmCallback callback, + HashMap optionalKeyRequestParameters, + boolean multiSession, + int initialDrmRequestRetryCount) { Assertions.checkNotNull(uuid); Assertions.checkNotNull(mediaDrm); Assertions.checkArgument(!C.COMMON_PSSH_UUID.equals(uuid), "Use C.CLEARKEY_UUID instead"); @@ -266,8 +344,7 @@ public DefaultDrmSessionManager(UUID uuid, ExoMediaDrm mediaDrm, MediaDrmCall this.mediaDrm = mediaDrm; this.callback = callback; this.optionalKeyRequestParameters = optionalKeyRequestParameters; - this.eventHandler = eventHandler; - this.eventListener = eventListener; + this.eventDispatcher = new EventDispatcher(); this.multiSession = multiSession; this.initialDrmRequestRetryCount = initialDrmRequestRetryCount; mode = MODE_PLAYBACK; @@ -279,6 +356,25 @@ public DefaultDrmSessionManager(UUID uuid, ExoMediaDrm mediaDrm, MediaDrmCall mediaDrm.setOnEventListener(new MediaDrmEventListener()); } + /** + * Adds a {@link DefaultDrmSessionEventListener} to listen to drm session events. + * + * @param handler A handler to use when delivering events to {@code eventListener}. + * @param eventListener A listener of events. + */ + public final void addListener(Handler handler, DefaultDrmSessionEventListener eventListener) { + eventDispatcher.addListener(handler, eventListener); + } + + /** + * Removes a {@link DefaultDrmSessionEventListener} from the list of drm session event listeners. + * + * @param eventListener The listener to remove. + */ + public final void removeListener(DefaultDrmSessionEventListener eventListener) { + eventDispatcher.removeListener(eventListener); + } + /** * Provides access to {@link ExoMediaDrm#getPropertyString(String)}. *

@@ -406,15 +502,7 @@ public DrmSession acquireSession(Looper playbackLooper, DrmInitData drmInitDa SchemeData data = getSchemeData(drmInitData, uuid, false); if (data == null) { final MissingSchemeDataException error = new MissingSchemeDataException(uuid); - if (eventHandler != null && eventListener != null) { - eventHandler.post( - new Runnable() { - @Override - public void run() { - eventListener.onDrmSessionManagerError(error); - } - }); - } + eventDispatcher.drmSessionManagerError(error); return new ErrorStateDrmSession<>(new DrmSessionException(error)); } initData = getSchemeInitData(data, uuid); @@ -437,9 +525,20 @@ public void run() { if (session == null) { // Create a new session. - session = new DefaultDrmSession<>(uuid, mediaDrm, this, initData, mimeType, mode, - offlineLicenseKeySetId, optionalKeyRequestParameters, callback, playbackLooper, - eventHandler, eventListener, initialDrmRequestRetryCount); + session = + new DefaultDrmSession<>( + uuid, + mediaDrm, + this, + initData, + mimeType, + mode, + offlineLicenseKeySetId, + optionalKeyRequestParameters, + callback, + playbackLooper, + eventDispatcher, + initialDrmRequestRetryCount); sessions.add(session); } session.acquire(); diff --git a/library/core/src/main/java/com/google/android/exoplayer2/drm/OfflineLicenseHelper.java b/library/core/src/main/java/com/google/android/exoplayer2/drm/OfflineLicenseHelper.java index 481bea66c37..9298c16cb01 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/drm/OfflineLicenseHelper.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/drm/OfflineLicenseHelper.java @@ -21,7 +21,6 @@ import android.os.HandlerThread; import android.util.Pair; import com.google.android.exoplayer2.C; -import com.google.android.exoplayer2.drm.DefaultDrmSessionManager.EventListener; import com.google.android.exoplayer2.drm.DefaultDrmSessionManager.Mode; import com.google.android.exoplayer2.drm.DrmSession.DrmSessionException; import com.google.android.exoplayer2.upstream.HttpDataSource; @@ -90,10 +89,12 @@ public static OfflineLicenseHelper newWidevineInstance( * @throws UnsupportedDrmException If the Widevine DRM scheme is unsupported or cannot be * instantiated. * @see DefaultDrmSessionManager#DefaultDrmSessionManager(java.util.UUID, ExoMediaDrm, - * MediaDrmCallback, HashMap, Handler, EventListener) + * MediaDrmCallback, HashMap, Handler, DefaultDrmSessionEventListener) */ public static OfflineLicenseHelper newWidevineInstance( - String defaultLicenseUrl, boolean forceDefaultLicenseUrl, Factory httpDataSourceFactory, + String defaultLicenseUrl, + boolean forceDefaultLicenseUrl, + Factory httpDataSourceFactory, HashMap optionalKeyRequestParameters) throws UnsupportedDrmException { return new OfflineLicenseHelper<>(C.WIDEVINE_UUID, @@ -111,36 +112,41 @@ public static OfflineLicenseHelper newWidevineInstance( * @param optionalKeyRequestParameters An optional map of parameters to pass as the last argument * to {@link MediaDrm#getKeyRequest(byte[], byte[], String, int, HashMap)}. May be null. * @see DefaultDrmSessionManager#DefaultDrmSessionManager(java.util.UUID, ExoMediaDrm, - * MediaDrmCallback, HashMap, Handler, EventListener) + * MediaDrmCallback, HashMap, Handler, DefaultDrmSessionEventListener) */ - public OfflineLicenseHelper(UUID uuid, ExoMediaDrm mediaDrm, MediaDrmCallback callback, + public OfflineLicenseHelper( + UUID uuid, + ExoMediaDrm mediaDrm, + MediaDrmCallback callback, HashMap optionalKeyRequestParameters) { handlerThread = new HandlerThread("OfflineLicenseHelper"); handlerThread.start(); conditionVariable = new ConditionVariable(); - EventListener eventListener = new EventListener() { - @Override - public void onDrmKeysLoaded() { - conditionVariable.open(); - } + DefaultDrmSessionEventListener eventListener = + new DefaultDrmSessionEventListener() { + @Override + public void onDrmKeysLoaded() { + conditionVariable.open(); + } - @Override - public void onDrmSessionManagerError(Exception e) { - conditionVariable.open(); - } + @Override + public void onDrmSessionManagerError(Exception e) { + conditionVariable.open(); + } - @Override - public void onDrmKeysRestored() { - conditionVariable.open(); - } + @Override + public void onDrmKeysRestored() { + conditionVariable.open(); + } - @Override - public void onDrmKeysRemoved() { - conditionVariable.open(); - } - }; - drmSessionManager = new DefaultDrmSessionManager<>(uuid, mediaDrm, callback, - optionalKeyRequestParameters, new Handler(handlerThread.getLooper()), eventListener); + @Override + public void onDrmKeysRemoved() { + conditionVariable.open(); + } + }; + drmSessionManager = + new DefaultDrmSessionManager<>(uuid, mediaDrm, callback, optionalKeyRequestParameters); + drmSessionManager.addListener(new Handler(handlerThread.getLooper()), eventListener); } /** diff --git a/library/core/src/main/java/com/google/android/exoplayer2/util/EventLogger.java b/library/core/src/main/java/com/google/android/exoplayer2/util/EventLogger.java index dbe5b0b6a75..948033ceae6 100644 --- a/library/core/src/main/java/com/google/android/exoplayer2/util/EventLogger.java +++ b/library/core/src/main/java/com/google/android/exoplayer2/util/EventLogger.java @@ -27,7 +27,7 @@ import com.google.android.exoplayer2.Timeline; import com.google.android.exoplayer2.audio.AudioRendererEventListener; import com.google.android.exoplayer2.decoder.DecoderCounters; -import com.google.android.exoplayer2.drm.DefaultDrmSessionManager; +import com.google.android.exoplayer2.drm.DefaultDrmSessionEventListener; import com.google.android.exoplayer2.metadata.Metadata; import com.google.android.exoplayer2.metadata.MetadataOutput; import com.google.android.exoplayer2.metadata.emsg.EventMessage; @@ -60,7 +60,7 @@ public class EventLogger VideoRendererEventListener, MediaSourceEventListener, AdsMediaSource.EventListener, - DefaultDrmSessionManager.EventListener { + DefaultDrmSessionEventListener { private static final String TAG = "EventLogger"; private static final int MAX_TIMELINE_ITEM_LINES = 3; diff --git a/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashTestRunner.java b/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashTestRunner.java index e846a377dcd..f121ef944da 100644 --- a/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashTestRunner.java +++ b/playbacktests/src/androidTest/java/com/google/android/exoplayer2/playbacktests/gts/DashTestRunner.java @@ -279,7 +279,7 @@ protected DefaultDrmSessionManager buildDrmSessionManager( MediaDrmCallback drmCallback = new HttpMediaDrmCallback(widevineLicenseUrl, new DefaultHttpDataSourceFactory(userAgent)); DefaultDrmSessionManager drmSessionManager = - DefaultDrmSessionManager.newWidevineInstance(drmCallback, null, null, null); + DefaultDrmSessionManager.newWidevineInstance(drmCallback, null); if (!useL1Widevine) { drmSessionManager.setPropertyString( SECURITY_LEVEL_PROPERTY, WIDEVINE_SECURITY_LEVEL_3);