De-duplicate DRM acquire & release events by EventDispatcher

When we add DRM pre-acquire support to SampleQueue, we'll dispatch
twice the number of acquire and release events. This is slightly
confusing, since there's the same number of
DrmSessionManager#acquireSession() calls.

We can mitigate this by only dispatching each acquire and release
event to at most one EventDispatcher.

This also changes the events fired when playing a stream with both audio
and video encrypted with the same keys (even without pre-acquisition).

Before: The EventDispatcher would see 2 aquires, 1 key load and 2
release events.

After: The EventDispatcher will see 1 acquire, 1 key load and 1 release.
PiperOrigin-RevId: 358804502
This commit is contained in:
ibaker 2021-02-22 14:17:07 +00:00 committed by marcbaechinger
parent 0eed19d8a3
commit 623597addb
4 changed files with 31 additions and 4 deletions

View File

@ -32,6 +32,11 @@
* Fix a bug with playback of ads in playlists, where the incorrect period * Fix a bug with playback of ads in playlists, where the incorrect period
index was used when deciding whether to trigger playback of an ad after index was used when deciding whether to trigger playback of an ad after
a seek. a seek.
* DRM:
* Only dispatch DRM session acquire and release events once per period
when playing content that uses the same encryption keys for both audio &
video tracks (previously separate acquire and release events were
dispatched for each track in each period).
* VP9 extension: Update to use NDK r22 * VP9 extension: Update to use NDK r22
([#8581](https://github.com/google/ExoPlayer/issues/8581)). ([#8581](https://github.com/google/ExoPlayer/issues/8581)).
* FLAC extension: Update to use NDK r22 * FLAC extension: Update to use NDK r22

View File

@ -138,4 +138,11 @@ public final class CopyOnWriteMultiset<E extends Object> implements Iterable<E>
return elements.iterator(); return elements.iterator();
} }
} }
/** Returns the number of occurrences of an element in this multiset. */
public int count(E element) {
synchronized (lock) {
return elementCounts.containsKey(element) ? elementCounts.get(element) : 0;
}
}
} }

View File

@ -107,4 +107,14 @@ public final class CopyOnWriteMultisetTest {
assertThrows(UnsupportedOperationException.class, () -> elementSet.remove("a string")); assertThrows(UnsupportedOperationException.class, () -> elementSet.remove("a string"));
} }
@Test
public void count() {
CopyOnWriteMultiset<String> multiset = new CopyOnWriteMultiset<>();
multiset.add("a string");
multiset.add("a string");
assertThat(multiset.count("a string")).isEqualTo(2);
assertThat(multiset.count("another string")).isEqualTo(0);
}
} }

View File

@ -293,8 +293,11 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
if (openInternal(true)) { if (openInternal(true)) {
doLicense(true); doLicense(true);
} }
} else if (eventDispatcher != null && isOpen()) { } else if (eventDispatcher != null
// If the session is already open then send the acquire event only to the provided dispatcher. && isOpen()
&& eventDispatchers.count(eventDispatcher) == 1) {
// If the session is already open and this is the first instance of eventDispatcher we've
// seen, then send the acquire event only to the provided dispatcher.
// TODO: Add a parameter to onDrmSessionAcquired to indicate whether the session is being // TODO: Add a parameter to onDrmSessionAcquired to indicate whether the session is being
// re-used or not. // re-used or not.
eventDispatcher.drmSessionAcquired(); eventDispatcher.drmSessionAcquired();
@ -323,9 +326,11 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
} }
} }
if (eventDispatcher != null) { if (eventDispatcher != null) {
// Acquire and release events are only sent to the provided dispatcher.
eventDispatcher.drmSessionReleased();
eventDispatchers.remove(eventDispatcher); eventDispatchers.remove(eventDispatcher);
if (eventDispatchers.count(eventDispatcher) == 0) {
// Release events are only sent to the last-attached instance of each EventDispatcher.
eventDispatcher.drmSessionReleased();
}
} }
referenceCountListener.onReferenceCountDecremented(this, referenceCount); referenceCountListener.onReferenceCountDecremented(this, referenceCount);
} }