mirror of
https://github.com/samsonjs/media.git
synced 2026-04-02 10:45:51 +00:00
Completely separate MediaSource & DrmSession EventDispatchers
PiperOrigin-RevId: 319989989
This commit is contained in:
parent
4c75339ee8
commit
fa594489d9
46 changed files with 878 additions and 868 deletions
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Copyright (C) 2020 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.util;
|
||||
|
||||
/**
|
||||
* Represents an operation that accepts a single input argument and returns no result. Unlike most
|
||||
* other functional interfaces, Consumer is expected to operate via side-effects.
|
||||
*/
|
||||
public interface Consumer<T> {
|
||||
|
||||
/** Performs this operation on the given argument. */
|
||||
void accept(T t);
|
||||
}
|
||||
|
|
@ -70,7 +70,8 @@ import java.util.Set;
|
|||
private final IdentityHashMap<MediaPeriod, MediaSourceHolder> mediaSourceByMediaPeriod;
|
||||
private final Map<Object, MediaSourceHolder> mediaSourceByUid;
|
||||
private final MediaSourceListInfoRefreshListener mediaSourceListInfoListener;
|
||||
private final MediaSourceEventListener.EventDispatcher eventDispatcher;
|
||||
private final MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher;
|
||||
private final DrmSessionEventListener.EventDispatcher drmEventDispatcher;
|
||||
private final HashMap<MediaSourceList.MediaSourceHolder, MediaSourceAndListener> childSources;
|
||||
private final Set<MediaSourceHolder> enabledMediaSourceHolders;
|
||||
|
||||
|
|
@ -98,14 +99,13 @@ import java.util.Set;
|
|||
mediaSourceByMediaPeriod = new IdentityHashMap<>();
|
||||
mediaSourceByUid = new HashMap<>();
|
||||
mediaSourceHolders = new ArrayList<>();
|
||||
eventDispatcher = new MediaSourceEventListener.EventDispatcher();
|
||||
mediaSourceEventDispatcher = new MediaSourceEventListener.EventDispatcher();
|
||||
drmEventDispatcher = new DrmSessionEventListener.EventDispatcher();
|
||||
childSources = new HashMap<>();
|
||||
enabledMediaSourceHolders = new HashSet<>();
|
||||
if (analyticsCollector != null) {
|
||||
eventDispatcher.addEventListener(
|
||||
analyticsCollectorHandler, analyticsCollector, MediaSourceEventListener.class);
|
||||
eventDispatcher.addEventListener(
|
||||
analyticsCollectorHandler, analyticsCollector, DrmSessionEventListener.class);
|
||||
mediaSourceEventDispatcher.addEventListener(analyticsCollectorHandler, analyticsCollector);
|
||||
drmEventDispatcher.addEventListener(analyticsCollectorHandler, analyticsCollector);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -523,10 +523,12 @@ import java.util.Set;
|
|||
implements MediaSourceEventListener, DrmSessionEventListener {
|
||||
|
||||
private final MediaSourceList.MediaSourceHolder id;
|
||||
private EventDispatcher eventDispatcher;
|
||||
private MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher;
|
||||
private DrmSessionEventListener.EventDispatcher drmEventDispatcher;
|
||||
|
||||
public ForwardingEventListener(MediaSourceList.MediaSourceHolder id) {
|
||||
eventDispatcher = MediaSourceList.this.eventDispatcher;
|
||||
mediaSourceEventDispatcher = MediaSourceList.this.mediaSourceEventDispatcher;
|
||||
drmEventDispatcher = MediaSourceList.this.drmEventDispatcher;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
|
|
@ -535,14 +537,14 @@ import java.util.Set;
|
|||
@Override
|
||||
public void onMediaPeriodCreated(int windowIndex, MediaSource.MediaPeriodId mediaPeriodId) {
|
||||
if (maybeUpdateEventDispatcher(windowIndex, mediaPeriodId)) {
|
||||
eventDispatcher.mediaPeriodCreated();
|
||||
mediaSourceEventDispatcher.mediaPeriodCreated();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMediaPeriodReleased(int windowIndex, MediaSource.MediaPeriodId mediaPeriodId) {
|
||||
if (maybeUpdateEventDispatcher(windowIndex, mediaPeriodId)) {
|
||||
eventDispatcher.mediaPeriodReleased();
|
||||
mediaSourceEventDispatcher.mediaPeriodReleased();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -553,7 +555,7 @@ import java.util.Set;
|
|||
LoadEventInfo loadEventData,
|
||||
MediaLoadData mediaLoadData) {
|
||||
if (maybeUpdateEventDispatcher(windowIndex, mediaPeriodId)) {
|
||||
eventDispatcher.loadStarted(loadEventData, mediaLoadData);
|
||||
mediaSourceEventDispatcher.loadStarted(loadEventData, mediaLoadData);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -564,7 +566,7 @@ import java.util.Set;
|
|||
LoadEventInfo loadEventData,
|
||||
MediaLoadData mediaLoadData) {
|
||||
if (maybeUpdateEventDispatcher(windowIndex, mediaPeriodId)) {
|
||||
eventDispatcher.loadCompleted(loadEventData, mediaLoadData);
|
||||
mediaSourceEventDispatcher.loadCompleted(loadEventData, mediaLoadData);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -575,7 +577,7 @@ import java.util.Set;
|
|||
LoadEventInfo loadEventData,
|
||||
MediaLoadData mediaLoadData) {
|
||||
if (maybeUpdateEventDispatcher(windowIndex, mediaPeriodId)) {
|
||||
eventDispatcher.loadCanceled(loadEventData, mediaLoadData);
|
||||
mediaSourceEventDispatcher.loadCanceled(loadEventData, mediaLoadData);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -588,14 +590,14 @@ import java.util.Set;
|
|||
IOException error,
|
||||
boolean wasCanceled) {
|
||||
if (maybeUpdateEventDispatcher(windowIndex, mediaPeriodId)) {
|
||||
eventDispatcher.loadError(loadEventData, mediaLoadData, error, wasCanceled);
|
||||
mediaSourceEventDispatcher.loadError(loadEventData, mediaLoadData, error, wasCanceled);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReadingStarted(int windowIndex, MediaSource.MediaPeriodId mediaPeriodId) {
|
||||
if (maybeUpdateEventDispatcher(windowIndex, mediaPeriodId)) {
|
||||
eventDispatcher.readingStarted();
|
||||
mediaSourceEventDispatcher.readingStarted();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -605,7 +607,7 @@ import java.util.Set;
|
|||
@Nullable MediaSource.MediaPeriodId mediaPeriodId,
|
||||
MediaLoadData mediaLoadData) {
|
||||
if (maybeUpdateEventDispatcher(windowIndex, mediaPeriodId)) {
|
||||
eventDispatcher.upstreamDiscarded(mediaLoadData);
|
||||
mediaSourceEventDispatcher.upstreamDiscarded(mediaLoadData);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -615,7 +617,7 @@ import java.util.Set;
|
|||
@Nullable MediaSource.MediaPeriodId mediaPeriodId,
|
||||
MediaLoadData mediaLoadData) {
|
||||
if (maybeUpdateEventDispatcher(windowIndex, mediaPeriodId)) {
|
||||
eventDispatcher.downstreamFormatChanged(mediaLoadData);
|
||||
mediaSourceEventDispatcher.downstreamFormatChanged(mediaLoadData);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -625,8 +627,7 @@ import java.util.Set;
|
|||
public void onDrmSessionAcquired(
|
||||
int windowIndex, @Nullable MediaSource.MediaPeriodId mediaPeriodId) {
|
||||
if (maybeUpdateEventDispatcher(windowIndex, mediaPeriodId)) {
|
||||
eventDispatcher.dispatch(
|
||||
DrmSessionEventListener::onDrmSessionAcquired, DrmSessionEventListener.class);
|
||||
drmEventDispatcher.drmSessionAcquired();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -634,8 +635,7 @@ import java.util.Set;
|
|||
public void onDrmKeysLoaded(
|
||||
int windowIndex, @Nullable MediaSource.MediaPeriodId mediaPeriodId) {
|
||||
if (maybeUpdateEventDispatcher(windowIndex, mediaPeriodId)) {
|
||||
eventDispatcher.dispatch(
|
||||
DrmSessionEventListener::onDrmKeysLoaded, DrmSessionEventListener.class);
|
||||
drmEventDispatcher.drmKeysLoaded();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -643,10 +643,7 @@ import java.util.Set;
|
|||
public void onDrmSessionManagerError(
|
||||
int windowIndex, @Nullable MediaSource.MediaPeriodId mediaPeriodId, Exception error) {
|
||||
if (maybeUpdateEventDispatcher(windowIndex, mediaPeriodId)) {
|
||||
eventDispatcher.dispatch(
|
||||
(listener, innerWindowIndex, innerMediaPeriodId) ->
|
||||
listener.onDrmSessionManagerError(innerWindowIndex, innerMediaPeriodId, error),
|
||||
DrmSessionEventListener.class);
|
||||
drmEventDispatcher.drmSessionManagerError(error);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -654,8 +651,7 @@ import java.util.Set;
|
|||
public void onDrmKeysRestored(
|
||||
int windowIndex, @Nullable MediaSource.MediaPeriodId mediaPeriodId) {
|
||||
if (maybeUpdateEventDispatcher(windowIndex, mediaPeriodId)) {
|
||||
eventDispatcher.dispatch(
|
||||
DrmSessionEventListener::onDrmKeysRestored, DrmSessionEventListener.class);
|
||||
drmEventDispatcher.drmKeysRestored();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -663,8 +659,7 @@ import java.util.Set;
|
|||
public void onDrmKeysRemoved(
|
||||
int windowIndex, @Nullable MediaSource.MediaPeriodId mediaPeriodId) {
|
||||
if (maybeUpdateEventDispatcher(windowIndex, mediaPeriodId)) {
|
||||
eventDispatcher.dispatch(
|
||||
DrmSessionEventListener::onDrmKeysRemoved, DrmSessionEventListener.class);
|
||||
drmEventDispatcher.drmKeysRemoved();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -672,8 +667,7 @@ import java.util.Set;
|
|||
public void onDrmSessionReleased(
|
||||
int windowIndex, @Nullable MediaSource.MediaPeriodId mediaPeriodId) {
|
||||
if (maybeUpdateEventDispatcher(windowIndex, mediaPeriodId)) {
|
||||
eventDispatcher.dispatch(
|
||||
DrmSessionEventListener::onDrmSessionReleased, DrmSessionEventListener.class);
|
||||
drmEventDispatcher.drmSessionReleased();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -689,12 +683,17 @@ import java.util.Set;
|
|||
}
|
||||
}
|
||||
int windowIndex = getWindowIndexForChildWindowIndex(id, childWindowIndex);
|
||||
if (eventDispatcher.windowIndex != windowIndex
|
||||
|| !Util.areEqual(eventDispatcher.mediaPeriodId, mediaPeriodId)) {
|
||||
eventDispatcher =
|
||||
MediaSourceList.this.eventDispatcher.withParameters(
|
||||
if (mediaSourceEventDispatcher.windowIndex != windowIndex
|
||||
|| !Util.areEqual(mediaSourceEventDispatcher.mediaPeriodId, mediaPeriodId)) {
|
||||
mediaSourceEventDispatcher =
|
||||
MediaSourceList.this.mediaSourceEventDispatcher.withParameters(
|
||||
windowIndex, mediaPeriodId, /* mediaTimeOffsetMs= */ 0L);
|
||||
}
|
||||
if (drmEventDispatcher.windowIndex != windowIndex
|
||||
|| !Util.areEqual(drmEventDispatcher.mediaPeriodId, mediaPeriodId)) {
|
||||
drmEventDispatcher =
|
||||
MediaSourceList.this.drmEventDispatcher.withParameters(windowIndex, mediaPeriodId);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,9 +34,9 @@ import com.google.android.exoplayer2.source.MediaLoadData;
|
|||
import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy;
|
||||
import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy.LoadErrorInfo;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Consumer;
|
||||
import com.google.android.exoplayer2.util.CopyOnWriteMultiset;
|
||||
import com.google.android.exoplayer2.util.Log;
|
||||
import com.google.android.exoplayer2.util.MediaSourceEventDispatcher;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
|
|
@ -123,7 +123,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||
private final boolean playClearSamplesWithoutKeys;
|
||||
private final boolean isPlaceholderSession;
|
||||
private final HashMap<String, String> keyRequestParameters;
|
||||
private final CopyOnWriteMultiset<MediaSourceEventDispatcher> eventDispatchers;
|
||||
private final CopyOnWriteMultiset<DrmSessionEventListener.EventDispatcher> eventDispatchers;
|
||||
private final LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
||||
|
||||
/* package */ final MediaDrmCallback callback;
|
||||
|
|
@ -271,7 +271,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||
}
|
||||
|
||||
@Override
|
||||
public void acquire(@Nullable MediaSourceEventDispatcher eventDispatcher) {
|
||||
public void acquire(@Nullable DrmSessionEventListener.EventDispatcher eventDispatcher) {
|
||||
Assertions.checkState(referenceCount >= 0);
|
||||
if (eventDispatcher != null) {
|
||||
eventDispatchers.add(eventDispatcher);
|
||||
|
|
@ -288,14 +288,13 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||
// If the session is already open then send the acquire event only to the provided dispatcher.
|
||||
// TODO: Add a parameter to onDrmSessionAcquired to indicate whether the session is being
|
||||
// re-used or not.
|
||||
eventDispatcher.dispatch(
|
||||
DrmSessionEventListener::onDrmSessionAcquired, DrmSessionEventListener.class);
|
||||
eventDispatcher.drmSessionAcquired();
|
||||
}
|
||||
referenceCountListener.onReferenceCountIncremented(this, referenceCount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release(@Nullable MediaSourceEventDispatcher eventDispatcher) {
|
||||
public void release(@Nullable DrmSessionEventListener.EventDispatcher eventDispatcher) {
|
||||
if (--referenceCount == 0) {
|
||||
// Assigning null to various non-null variables for clean-up.
|
||||
state = STATE_RELEASED;
|
||||
|
|
@ -312,14 +311,13 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||
mediaDrm.closeSession(sessionId);
|
||||
sessionId = null;
|
||||
}
|
||||
dispatchEvent(DrmSessionEventListener::onDrmSessionReleased);
|
||||
dispatchEvent(DrmSessionEventListener.EventDispatcher::drmSessionReleased);
|
||||
}
|
||||
if (eventDispatcher != null) {
|
||||
if (isOpen()) {
|
||||
// If the session is still open then send the release event only to the provided dispatcher
|
||||
// before removing it.
|
||||
eventDispatcher.dispatch(
|
||||
DrmSessionEventListener::onDrmSessionReleased, DrmSessionEventListener.class);
|
||||
eventDispatcher.drmSessionReleased();
|
||||
}
|
||||
eventDispatchers.remove(eventDispatcher);
|
||||
}
|
||||
|
|
@ -345,7 +343,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||
try {
|
||||
sessionId = mediaDrm.openSession();
|
||||
mediaCrypto = mediaDrm.createMediaCrypto(sessionId);
|
||||
dispatchEvent(DrmSessionEventListener::onDrmSessionAcquired);
|
||||
dispatchEvent(DrmSessionEventListener.EventDispatcher::drmSessionAcquired);
|
||||
state = STATE_OPENED;
|
||||
Assertions.checkNotNull(sessionId);
|
||||
return true;
|
||||
|
|
@ -409,7 +407,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||
onError(new KeysExpiredException());
|
||||
} else {
|
||||
state = STATE_OPENED_WITH_KEYS;
|
||||
dispatchEvent(DrmSessionEventListener::onDrmKeysRestored);
|
||||
dispatchEvent(DrmSessionEventListener.EventDispatcher::drmKeysRestored);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
@ -479,7 +477,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||
byte[] responseData = (byte[]) response;
|
||||
if (mode == DefaultDrmSessionManager.MODE_RELEASE) {
|
||||
mediaDrm.provideKeyResponse(Util.castNonNull(offlineLicenseKeySetId), responseData);
|
||||
dispatchEvent(DrmSessionEventListener::onDrmKeysRemoved);
|
||||
dispatchEvent(DrmSessionEventListener.EventDispatcher::drmKeysRemoved);
|
||||
} else {
|
||||
byte[] keySetId = mediaDrm.provideKeyResponse(sessionId, responseData);
|
||||
if ((mode == DefaultDrmSessionManager.MODE_DOWNLOAD
|
||||
|
|
@ -490,7 +488,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||
offlineLicenseKeySetId = keySetId;
|
||||
}
|
||||
state = STATE_OPENED_WITH_KEYS;
|
||||
dispatchEvent(DrmSessionEventListener::onDrmKeysLoaded);
|
||||
dispatchEvent(DrmSessionEventListener.EventDispatcher::drmKeysLoaded);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
onKeysError(e);
|
||||
|
|
@ -514,9 +512,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||
|
||||
private void onError(final Exception e) {
|
||||
lastException = new DrmSessionException(e);
|
||||
dispatchEvent(
|
||||
(listener, windowIndex, mediaPeriodId) ->
|
||||
listener.onDrmSessionManagerError(windowIndex, mediaPeriodId, e));
|
||||
dispatchEvent(eventDispatcher -> eventDispatcher.drmSessionManagerError(e));
|
||||
if (state != STATE_OPENED_WITH_KEYS) {
|
||||
state = STATE_ERROR;
|
||||
}
|
||||
|
|
@ -528,10 +524,9 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||
return state == STATE_OPENED || state == STATE_OPENED_WITH_KEYS;
|
||||
}
|
||||
|
||||
private void dispatchEvent(
|
||||
MediaSourceEventDispatcher.EventWithPeriodId<DrmSessionEventListener> event) {
|
||||
for (MediaSourceEventDispatcher eventDispatcher : eventDispatchers.elementSet()) {
|
||||
eventDispatcher.dispatch(event, DrmSessionEventListener.class);
|
||||
private void dispatchEvent(Consumer<DrmSessionEventListener.EventDispatcher> event) {
|
||||
for (DrmSessionEventListener.EventDispatcher eventDispatcher : eventDispatchers.elementSet()) {
|
||||
event.accept(eventDispatcher);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ import com.google.android.exoplayer2.upstream.DefaultLoadErrorHandlingPolicy;
|
|||
import com.google.android.exoplayer2.upstream.LoadErrorHandlingPolicy;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Log;
|
||||
import com.google.android.exoplayer2.util.MediaSourceEventDispatcher;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.Sets;
|
||||
|
|
@ -406,8 +405,8 @@ public class DefaultDrmSessionManager implements DrmSessionManager {
|
|||
|
||||
/**
|
||||
* Sets the mode, which determines the role of sessions acquired from the instance. This must be
|
||||
* called before {@link #acquireSession(Looper, MediaSourceEventDispatcher, DrmInitData)} or
|
||||
* {@link #acquirePlaceholderSession} is called.
|
||||
* called before {@link #acquireSession(Looper, DrmSessionEventListener.EventDispatcher,
|
||||
* DrmInitData)} or {@link #acquirePlaceholderSession} is called.
|
||||
*
|
||||
* <p>By default, the mode is {@link #MODE_PLAYBACK} and a streaming license is requested when
|
||||
* required.
|
||||
|
|
@ -527,7 +526,7 @@ public class DefaultDrmSessionManager implements DrmSessionManager {
|
|||
@Override
|
||||
public DrmSession acquireSession(
|
||||
Looper playbackLooper,
|
||||
@Nullable MediaSourceEventDispatcher eventDispatcher,
|
||||
@Nullable DrmSessionEventListener.EventDispatcher eventDispatcher,
|
||||
DrmInitData drmInitData) {
|
||||
initPlaybackLooper(playbackLooper);
|
||||
maybeCreateMediaDrmHandler(playbackLooper);
|
||||
|
|
@ -538,10 +537,7 @@ public class DefaultDrmSessionManager implements DrmSessionManager {
|
|||
if (schemeDatas.isEmpty()) {
|
||||
final MissingSchemeDataException error = new MissingSchemeDataException(uuid);
|
||||
if (eventDispatcher != null) {
|
||||
eventDispatcher.dispatch(
|
||||
(listener, windowIndex, mediaPeriodId) ->
|
||||
listener.onDrmSessionManagerError(windowIndex, mediaPeriodId, error),
|
||||
DrmSessionEventListener.class);
|
||||
eventDispatcher.drmSessionManagerError(error);
|
||||
}
|
||||
return new ErrorStateDrmSession(new DrmSessionException(error));
|
||||
}
|
||||
|
|
@ -605,7 +601,7 @@ public class DefaultDrmSessionManager implements DrmSessionManager {
|
|||
private DefaultDrmSession createAndAcquireSessionWithRetry(
|
||||
@Nullable List<SchemeData> schemeDatas,
|
||||
boolean isPlaceholderSession,
|
||||
@Nullable MediaSourceEventDispatcher eventDispatcher) {
|
||||
@Nullable DrmSessionEventListener.EventDispatcher eventDispatcher) {
|
||||
DefaultDrmSession session =
|
||||
createAndAcquireSession(schemeDatas, isPlaceholderSession, eventDispatcher);
|
||||
if (session.getState() == DrmSession.STATE_ERROR
|
||||
|
|
@ -644,7 +640,7 @@ public class DefaultDrmSessionManager implements DrmSessionManager {
|
|||
private DefaultDrmSession createAndAcquireSession(
|
||||
@Nullable List<SchemeData> schemeDatas,
|
||||
boolean isPlaceholderSession,
|
||||
@Nullable MediaSourceEventDispatcher eventDispatcher) {
|
||||
@Nullable DrmSessionEventListener.EventDispatcher eventDispatcher) {
|
||||
Assertions.checkNotNull(exoMediaDrm);
|
||||
// Placeholder sessions should always play clear samples without keys.
|
||||
boolean playClearSamplesWithoutKeys = this.playClearSamplesWithoutKeys | isPlaceholderSession;
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ package com.google.android.exoplayer2.drm;
|
|||
import android.media.MediaDrm;
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.util.MediaSourceEventDispatcher;
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
|
|
@ -31,10 +30,10 @@ public interface DrmSession {
|
|||
/**
|
||||
* Acquires {@code newSession} then releases {@code previousSession}.
|
||||
*
|
||||
* <p>Invokes {@code newSession's} {@link #acquire(MediaSourceEventDispatcher)} and {@code
|
||||
* previousSession's} {@link #release(MediaSourceEventDispatcher)} in that order (passing {@code
|
||||
* eventDispatcher = null}). Null arguments are ignored. Does nothing if {@code previousSession}
|
||||
* and {@code newSession} are the same session.
|
||||
* <p>Invokes {@code newSession's} {@link #acquire(DrmSessionEventListener.EventDispatcher)} and
|
||||
* {@code previousSession's} {@link #release(DrmSessionEventListener.EventDispatcher)} in that
|
||||
* order (passing {@code eventDispatcher = null}). Null arguments are ignored. Does nothing if
|
||||
* {@code previousSession} and {@code newSession} are the same session.
|
||||
*/
|
||||
static void replaceSession(
|
||||
@Nullable DrmSession previousSession, @Nullable DrmSession newSession) {
|
||||
|
|
@ -134,20 +133,21 @@ public interface DrmSession {
|
|||
|
||||
/**
|
||||
* Increments the reference count. When the caller no longer needs to use the instance, it must
|
||||
* call {@link #release(MediaSourceEventDispatcher)} to decrement the reference count.
|
||||
* call {@link #release(DrmSessionEventListener.EventDispatcher)} to decrement the reference
|
||||
* count.
|
||||
*
|
||||
* @param eventDispatcher The {@link MediaSourceEventDispatcher} used to route DRM-related events
|
||||
* dispatched from this session, or null if no event handling is needed.
|
||||
* @param eventDispatcher The {@link DrmSessionEventListener.EventDispatcher} used to route
|
||||
* DRM-related events dispatched from this session, or null if no event handling is needed.
|
||||
*/
|
||||
void acquire(@Nullable MediaSourceEventDispatcher eventDispatcher);
|
||||
void acquire(@Nullable DrmSessionEventListener.EventDispatcher eventDispatcher);
|
||||
|
||||
/**
|
||||
* Decrements the reference count. If the reference count drops to 0 underlying resources are
|
||||
* released, and the instance cannot be re-used.
|
||||
*
|
||||
* @param eventDispatcher The {@link MediaSourceEventDispatcher} to disconnect when the session is
|
||||
* released (the same instance (possibly null) that was passed by the caller to {@link
|
||||
* #acquire(MediaSourceEventDispatcher)}).
|
||||
* @param eventDispatcher The {@link DrmSessionEventListener.EventDispatcher} to disconnect when
|
||||
* the session is released (the same instance (possibly null) that was passed by the caller to
|
||||
* {@link #acquire(DrmSessionEventListener.EventDispatcher)}).
|
||||
*/
|
||||
void release(@Nullable MediaSourceEventDispatcher eventDispatcher);
|
||||
void release(@Nullable DrmSessionEventListener.EventDispatcher eventDispatcher);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,9 +15,14 @@
|
|||
*/
|
||||
package com.google.android.exoplayer2.drm;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import androidx.annotation.CheckResult;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.Player;
|
||||
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
/** Listener of {@link DrmSessionManager} events. */
|
||||
public interface DrmSessionEventListener {
|
||||
|
|
@ -78,4 +83,148 @@ public interface DrmSessionEventListener {
|
|||
* @param mediaPeriodId The {@link MediaPeriodId} associated with the drm session.
|
||||
*/
|
||||
default void onDrmSessionReleased(int windowIndex, @Nullable MediaPeriodId mediaPeriodId) {}
|
||||
|
||||
/** Dispatches events to {@link DrmSessionEventListener DrmSessionEventListeners}. */
|
||||
class EventDispatcher {
|
||||
|
||||
/** The timeline window index reported with the events. */
|
||||
public final int windowIndex;
|
||||
/** The {@link MediaPeriodId} reported with the events. */
|
||||
@Nullable public final MediaPeriodId mediaPeriodId;
|
||||
|
||||
private final CopyOnWriteArrayList<EventDispatcher.ListenerAndHandler> listenerAndHandlers;
|
||||
|
||||
/** Creates an event dispatcher. */
|
||||
public EventDispatcher() {
|
||||
this(
|
||||
/* listenerAndHandlers= */ new CopyOnWriteArrayList<>(),
|
||||
/* windowIndex= */ 0,
|
||||
/* mediaPeriodId= */ null);
|
||||
}
|
||||
|
||||
private EventDispatcher(
|
||||
CopyOnWriteArrayList<EventDispatcher.ListenerAndHandler> listenerAndHandlers,
|
||||
int windowIndex,
|
||||
@Nullable MediaPeriodId mediaPeriodId) {
|
||||
this.listenerAndHandlers = listenerAndHandlers;
|
||||
this.windowIndex = windowIndex;
|
||||
this.mediaPeriodId = mediaPeriodId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a view of the event dispatcher with the provided window index and media period id.
|
||||
*
|
||||
* @param windowIndex The timeline window index to be reported with the events.
|
||||
* @param mediaPeriodId The {@link MediaPeriodId} to be reported with the events.
|
||||
* @return A view of the event dispatcher with the pre-configured parameters.
|
||||
*/
|
||||
@CheckResult
|
||||
public EventDispatcher withParameters(int windowIndex, @Nullable MediaPeriodId mediaPeriodId) {
|
||||
return new EventDispatcher(listenerAndHandlers, windowIndex, mediaPeriodId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a listener to the event dispatcher.
|
||||
*
|
||||
* @param handler A handler on the which listener events will be posted.
|
||||
* @param eventListener The listener to be added.
|
||||
*/
|
||||
public void addEventListener(Handler handler, DrmSessionEventListener eventListener) {
|
||||
Assertions.checkNotNull(handler);
|
||||
Assertions.checkNotNull(eventListener);
|
||||
listenerAndHandlers.add(new ListenerAndHandler(handler, eventListener));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a listener from the event dispatcher.
|
||||
*
|
||||
* @param eventListener The listener to be removed.
|
||||
*/
|
||||
public void removeEventListener(DrmSessionEventListener eventListener) {
|
||||
for (ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
|
||||
if (listenerAndHandler.listener == eventListener) {
|
||||
listenerAndHandlers.remove(listenerAndHandler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Dispatches {@link #onDrmSessionAcquired(int, MediaPeriodId)}. */
|
||||
public void drmSessionAcquired() {
|
||||
for (ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
|
||||
DrmSessionEventListener listener = listenerAndHandler.listener;
|
||||
postOrRun(
|
||||
listenerAndHandler.handler,
|
||||
() -> listener.onDrmSessionAcquired(windowIndex, mediaPeriodId));
|
||||
}
|
||||
}
|
||||
|
||||
/** Dispatches {@link #onDrmKeysLoaded(int, MediaPeriodId)}. */
|
||||
public void drmKeysLoaded() {
|
||||
for (ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
|
||||
DrmSessionEventListener listener = listenerAndHandler.listener;
|
||||
postOrRun(
|
||||
listenerAndHandler.handler, () -> listener.onDrmKeysLoaded(windowIndex, mediaPeriodId));
|
||||
}
|
||||
}
|
||||
|
||||
/** Dispatches {@link #onDrmSessionManagerError(int, MediaPeriodId, Exception)}. */
|
||||
public void drmSessionManagerError(Exception error) {
|
||||
for (ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
|
||||
DrmSessionEventListener listener = listenerAndHandler.listener;
|
||||
postOrRun(
|
||||
listenerAndHandler.handler,
|
||||
() -> listener.onDrmSessionManagerError(windowIndex, mediaPeriodId, error));
|
||||
}
|
||||
}
|
||||
|
||||
/** Dispatches {@link #onDrmKeysRestored(int, MediaPeriodId)}. */
|
||||
public void drmKeysRestored() {
|
||||
for (ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
|
||||
DrmSessionEventListener listener = listenerAndHandler.listener;
|
||||
postOrRun(
|
||||
listenerAndHandler.handler,
|
||||
() -> listener.onDrmKeysRestored(windowIndex, mediaPeriodId));
|
||||
}
|
||||
}
|
||||
|
||||
/** Dispatches {@link #onDrmKeysRemoved(int, MediaPeriodId)}. */
|
||||
public void drmKeysRemoved() {
|
||||
for (ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
|
||||
DrmSessionEventListener listener = listenerAndHandler.listener;
|
||||
postOrRun(
|
||||
listenerAndHandler.handler,
|
||||
() -> listener.onDrmKeysRemoved(windowIndex, mediaPeriodId));
|
||||
}
|
||||
}
|
||||
|
||||
/** Dispatches {@link #onDrmSessionReleased(int, MediaPeriodId)}. */
|
||||
public void drmSessionReleased() {
|
||||
for (ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
|
||||
DrmSessionEventListener listener = listenerAndHandler.listener;
|
||||
postOrRun(
|
||||
listenerAndHandler.handler,
|
||||
() -> listener.onDrmSessionReleased(windowIndex, mediaPeriodId));
|
||||
}
|
||||
}
|
||||
|
||||
/** Dispatches {@link #onDrmSessionAcquired(int, MediaPeriodId)}. */
|
||||
private static void postOrRun(Handler handler, Runnable runnable) {
|
||||
if (handler.getLooper() == Looper.myLooper()) {
|
||||
runnable.run();
|
||||
} else {
|
||||
handler.post(runnable);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class ListenerAndHandler {
|
||||
|
||||
public Handler handler;
|
||||
public DrmSessionEventListener listener;
|
||||
|
||||
public ListenerAndHandler(Handler handler, DrmSessionEventListener listener) {
|
||||
this.handler = handler;
|
||||
this.listener = listener;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ import android.os.Looper;
|
|||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.drm.DrmInitData.SchemeData;
|
||||
import com.google.android.exoplayer2.util.MediaSourceEventDispatcher;
|
||||
|
||||
/** Manages a DRM session. */
|
||||
public interface DrmSessionManager {
|
||||
|
|
@ -41,7 +40,7 @@ public interface DrmSessionManager {
|
|||
@Override
|
||||
public DrmSession acquireSession(
|
||||
Looper playbackLooper,
|
||||
@Nullable MediaSourceEventDispatcher eventDispatcher,
|
||||
@Nullable DrmSessionEventListener.EventDispatcher eventDispatcher,
|
||||
DrmInitData drmInitData) {
|
||||
return new ErrorStateDrmSession(
|
||||
new DrmSession.DrmSessionException(
|
||||
|
|
@ -83,7 +82,7 @@ public interface DrmSessionManager {
|
|||
/**
|
||||
* Returns a {@link DrmSession} that does not execute key requests, with an incremented reference
|
||||
* count. When the caller no longer needs to use the instance, it must call {@link
|
||||
* DrmSession#release(MediaSourceEventDispatcher)} to decrement the reference count.
|
||||
* DrmSession#release(DrmSessionEventListener.EventDispatcher)} to decrement the reference count.
|
||||
*
|
||||
* <p>Placeholder {@link DrmSession DrmSessions} may be used to configure secure decoders for
|
||||
* playback of clear content periods. This can reduce the cost of transitioning between clear and
|
||||
|
|
@ -103,18 +102,19 @@ public interface DrmSessionManager {
|
|||
/**
|
||||
* Returns a {@link DrmSession} for the specified {@link DrmInitData}, with an incremented
|
||||
* reference count. When the caller no longer needs to use the instance, it must call {@link
|
||||
* DrmSession#release(MediaSourceEventDispatcher)} to decrement the reference count.
|
||||
* DrmSession#release(DrmSessionEventListener.EventDispatcher)} to decrement the reference count.
|
||||
*
|
||||
* @param playbackLooper The looper associated with the media playback thread.
|
||||
* @param eventDispatcher The {@link MediaSourceEventDispatcher} used to distribute events, and
|
||||
* passed on to {@link DrmSession#acquire(MediaSourceEventDispatcher)}.
|
||||
* @param eventDispatcher The {@link DrmSessionEventListener.EventDispatcher} used to distribute
|
||||
* events, and passed on to {@link
|
||||
* DrmSession#acquire(DrmSessionEventListener.EventDispatcher)}.
|
||||
* @param drmInitData DRM initialization data. All contained {@link SchemeData}s must contain
|
||||
* non-null {@link SchemeData#data}.
|
||||
* @return The DRM session.
|
||||
*/
|
||||
DrmSession acquireSession(
|
||||
Looper playbackLooper,
|
||||
@Nullable MediaSourceEventDispatcher eventDispatcher,
|
||||
@Nullable DrmSessionEventListener.EventDispatcher eventDispatcher,
|
||||
DrmInitData drmInitData);
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ package com.google.android.exoplayer2.drm;
|
|||
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.MediaSourceEventDispatcher;
|
||||
import java.util.Map;
|
||||
|
||||
/** A {@link DrmSession} that's in a terminal error state. */
|
||||
|
|
@ -64,12 +63,12 @@ public final class ErrorStateDrmSession implements DrmSession {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void acquire(@Nullable MediaSourceEventDispatcher eventDispatcher) {
|
||||
public void acquire(@Nullable DrmSessionEventListener.EventDispatcher eventDispatcher) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release(@Nullable MediaSourceEventDispatcher eventDispatcher) {
|
||||
public void release(@Nullable DrmSessionEventListener.EventDispatcher eventDispatcher) {
|
||||
// Do nothing.
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,6 @@ import com.google.android.exoplayer2.drm.DrmSession.DrmSessionException;
|
|||
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
|
||||
import com.google.android.exoplayer2.upstream.HttpDataSource;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.MediaSourceEventDispatcher;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
|
|
@ -40,7 +39,7 @@ public final class OfflineLicenseHelper {
|
|||
private final ConditionVariable conditionVariable;
|
||||
private final DefaultDrmSessionManager drmSessionManager;
|
||||
private final HandlerThread handlerThread;
|
||||
private final MediaSourceEventDispatcher eventDispatcher;
|
||||
private final DrmSessionEventListener.EventDispatcher eventDispatcher;
|
||||
|
||||
/**
|
||||
* Instantiates a new instance which uses Widevine CDM. Call {@link #release()} when the instance
|
||||
|
|
@ -49,14 +48,14 @@ public final class OfflineLicenseHelper {
|
|||
* @param defaultLicenseUrl The default license URL. Used for key requests that do not specify
|
||||
* their own license URL.
|
||||
* @param httpDataSourceFactory A factory from which to obtain {@link HttpDataSource} instances.
|
||||
* @param eventDispatcher A {@link MediaSourceEventDispatcher} used to distribute DRM-related
|
||||
* events.
|
||||
* @param eventDispatcher A {@link DrmSessionEventListener.EventDispatcher} used to distribute
|
||||
* DRM-related events.
|
||||
* @return A new instance which uses Widevine CDM.
|
||||
*/
|
||||
public static OfflineLicenseHelper newWidevineInstance(
|
||||
String defaultLicenseUrl,
|
||||
HttpDataSource.Factory httpDataSourceFactory,
|
||||
MediaSourceEventDispatcher eventDispatcher) {
|
||||
DrmSessionEventListener.EventDispatcher eventDispatcher) {
|
||||
return newWidevineInstance(
|
||||
defaultLicenseUrl,
|
||||
/* forceDefaultLicenseUrl= */ false,
|
||||
|
|
@ -73,15 +72,15 @@ public final class OfflineLicenseHelper {
|
|||
* @param forceDefaultLicenseUrl Whether to use {@code defaultLicenseUrl} for key requests that
|
||||
* include their own license URL.
|
||||
* @param httpDataSourceFactory A factory from which to obtain {@link HttpDataSource} instances.
|
||||
* @param eventDispatcher A {@link MediaSourceEventDispatcher} used to distribute DRM-related
|
||||
* events.
|
||||
* @param eventDispatcher A {@link DrmSessionEventListener.EventDispatcher} used to distribute
|
||||
* DRM-related events.
|
||||
* @return A new instance which uses Widevine CDM.
|
||||
*/
|
||||
public static OfflineLicenseHelper newWidevineInstance(
|
||||
String defaultLicenseUrl,
|
||||
boolean forceDefaultLicenseUrl,
|
||||
HttpDataSource.Factory httpDataSourceFactory,
|
||||
MediaSourceEventDispatcher eventDispatcher) {
|
||||
DrmSessionEventListener.EventDispatcher eventDispatcher) {
|
||||
return newWidevineInstance(
|
||||
defaultLicenseUrl,
|
||||
forceDefaultLicenseUrl,
|
||||
|
|
@ -100,8 +99,8 @@ public final class OfflineLicenseHelper {
|
|||
* include their own license URL.
|
||||
* @param optionalKeyRequestParameters An optional map of parameters to pass as the last argument
|
||||
* to {@link MediaDrm#getKeyRequest}. May be null.
|
||||
* @param eventDispatcher A {@link MediaSourceEventDispatcher} used to distribute DRM-related
|
||||
* events.
|
||||
* @param eventDispatcher A {@link DrmSessionEventListener.EventDispatcher} used to distribute
|
||||
* DRM-related events.
|
||||
* @return A new instance which uses Widevine CDM.
|
||||
* @see DefaultDrmSessionManager.Builder
|
||||
*/
|
||||
|
|
@ -110,7 +109,7 @@ public final class OfflineLicenseHelper {
|
|||
boolean forceDefaultLicenseUrl,
|
||||
HttpDataSource.Factory httpDataSourceFactory,
|
||||
@Nullable Map<String, String> optionalKeyRequestParameters,
|
||||
MediaSourceEventDispatcher eventDispatcher) {
|
||||
DrmSessionEventListener.EventDispatcher eventDispatcher) {
|
||||
return new OfflineLicenseHelper(
|
||||
new DefaultDrmSessionManager.Builder()
|
||||
.setKeyRequestParameters(optionalKeyRequestParameters)
|
||||
|
|
@ -122,7 +121,7 @@ public final class OfflineLicenseHelper {
|
|||
|
||||
/**
|
||||
* @deprecated Use {@link #OfflineLicenseHelper(DefaultDrmSessionManager,
|
||||
* MediaSourceEventDispatcher)} instead.
|
||||
* DrmSessionEventListener.EventDispatcher)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public OfflineLicenseHelper(
|
||||
|
|
@ -130,7 +129,7 @@ public final class OfflineLicenseHelper {
|
|||
ExoMediaDrm.Provider mediaDrmProvider,
|
||||
MediaDrmCallback callback,
|
||||
@Nullable Map<String, String> optionalKeyRequestParameters,
|
||||
MediaSourceEventDispatcher eventDispatcher) {
|
||||
DrmSessionEventListener.EventDispatcher eventDispatcher) {
|
||||
this(
|
||||
new DefaultDrmSessionManager.Builder()
|
||||
.setUuidAndExoMediaDrmProvider(uuid, mediaDrmProvider)
|
||||
|
|
@ -143,12 +142,12 @@ public final class OfflineLicenseHelper {
|
|||
* Constructs an instance. Call {@link #release()} when the instance is no longer required.
|
||||
*
|
||||
* @param defaultDrmSessionManager The {@link DefaultDrmSessionManager} used to download licenses.
|
||||
* @param eventDispatcher A {@link MediaSourceEventDispatcher} used to distribute DRM-related
|
||||
* events.
|
||||
* @param eventDispatcher A {@link DrmSessionEventListener.EventDispatcher} used to distribute
|
||||
* DRM-related events.
|
||||
*/
|
||||
public OfflineLicenseHelper(
|
||||
DefaultDrmSessionManager defaultDrmSessionManager,
|
||||
MediaSourceEventDispatcher eventDispatcher) {
|
||||
DrmSessionEventListener.EventDispatcher eventDispatcher) {
|
||||
this.drmSessionManager = defaultDrmSessionManager;
|
||||
this.eventDispatcher = eventDispatcher;
|
||||
handlerThread = new HandlerThread("ExoPlayer:OfflineLicenseHelper");
|
||||
|
|
@ -177,8 +176,7 @@ public final class OfflineLicenseHelper {
|
|||
conditionVariable.open();
|
||||
}
|
||||
};
|
||||
eventDispatcher.addEventListener(
|
||||
new Handler(handlerThread.getLooper()), eventListener, DrmSessionEventListener.class);
|
||||
eventDispatcher.addEventListener(new Handler(handlerThread.getLooper()), eventListener);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ import com.google.android.exoplayer2.Timeline;
|
|||
import com.google.android.exoplayer2.drm.DrmSessionEventListener;
|
||||
import com.google.android.exoplayer2.upstream.TransferListener;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.MediaSourceEventDispatcher;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
|
||||
|
|
@ -38,6 +37,7 @@ public abstract class BaseMediaSource implements MediaSource {
|
|||
private final ArrayList<MediaSourceCaller> mediaSourceCallers;
|
||||
private final HashSet<MediaSourceCaller> enabledMediaSourceCallers;
|
||||
private final MediaSourceEventListener.EventDispatcher eventDispatcher;
|
||||
private final DrmSessionEventListener.EventDispatcher drmEventDispatcher;
|
||||
|
||||
@Nullable private Looper looper;
|
||||
@Nullable private Timeline timeline;
|
||||
|
|
@ -46,6 +46,7 @@ public abstract class BaseMediaSource implements MediaSource {
|
|||
mediaSourceCallers = new ArrayList<>(/* initialCapacity= */ 1);
|
||||
enabledMediaSourceCallers = new HashSet<>(/* initialCapacity= */ 1);
|
||||
eventDispatcher = new MediaSourceEventListener.EventDispatcher();
|
||||
drmEventDispatcher = new DrmSessionEventListener.EventDispatcher();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -127,6 +128,33 @@ public abstract class BaseMediaSource implements MediaSource {
|
|||
return eventDispatcher.withParameters(windowIndex, mediaPeriodId, mediaTimeOffsetMs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link DrmSessionEventListener.EventDispatcher} which dispatches all events to the
|
||||
* registered listeners with the specified media period id.
|
||||
*
|
||||
* @param mediaPeriodId The {@link MediaPeriodId} to be reported with the events. May be null, if
|
||||
* the events do not belong to a specific media period.
|
||||
* @return An event dispatcher with pre-configured media period id.
|
||||
*/
|
||||
protected final DrmSessionEventListener.EventDispatcher createDrmEventDispatcher(
|
||||
@Nullable MediaPeriodId mediaPeriodId) {
|
||||
return drmEventDispatcher.withParameters(/* windowIndex= */ 0, mediaPeriodId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link DrmSessionEventListener.EventDispatcher} which dispatches all events to the
|
||||
* registered listeners with the specified window index and media period id.
|
||||
*
|
||||
* @param windowIndex The timeline window index to be reported with the events.
|
||||
* @param mediaPeriodId The {@link MediaPeriodId} to be reported with the events. May be null, if
|
||||
* the events do not belong to a specific media period.
|
||||
* @return An event dispatcher with pre-configured media period id and time offset.
|
||||
*/
|
||||
protected final DrmSessionEventListener.EventDispatcher createDrmEventDispatcher(
|
||||
int windowIndex, @Nullable MediaPeriodId mediaPeriodId) {
|
||||
return drmEventDispatcher.withParameters(windowIndex, mediaPeriodId);
|
||||
}
|
||||
|
||||
/** Returns whether the source is enabled. */
|
||||
protected final boolean isEnabled() {
|
||||
return !enabledMediaSourceCallers.isEmpty();
|
||||
|
|
@ -134,44 +162,22 @@ public abstract class BaseMediaSource implements MediaSource {
|
|||
|
||||
@Override
|
||||
public final void addEventListener(Handler handler, MediaSourceEventListener eventListener) {
|
||||
addEventListenerInternal(handler, eventListener, MediaSourceEventListener.class);
|
||||
eventDispatcher.addEventListener(handler, eventListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void removeEventListener(MediaSourceEventListener eventListener) {
|
||||
removeEventListenerInternal(eventListener, MediaSourceEventListener.class);
|
||||
eventDispatcher.removeEventListener(eventListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void addDrmEventListener(Handler handler, DrmSessionEventListener eventListener) {
|
||||
addEventListenerInternal(handler, eventListener, DrmSessionEventListener.class);
|
||||
drmEventDispatcher.addEventListener(handler, eventListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void removeDrmEventListener(DrmSessionEventListener eventListener) {
|
||||
removeEventListenerInternal(eventListener, DrmSessionEventListener.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a listener to the internal {@link MediaSourceEventDispatcher} with the provided type.
|
||||
*
|
||||
* <p>NOTE: Read the caveats on {@link MediaSourceEventDispatcher#addEventListener(Handler,
|
||||
* Object, Class)} when deciding what value to pass for {@code listenerClass}.
|
||||
*
|
||||
* @see MediaSourceEventDispatcher#addEventListener(Handler, Object, Class)
|
||||
*/
|
||||
protected final <T> void addEventListenerInternal(
|
||||
Handler handler, T eventListener, Class<T> listenerClass) {
|
||||
eventDispatcher.addEventListener(handler, eventListener, listenerClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a listener from the internal {@link MediaSourceEventDispatcher}.
|
||||
*
|
||||
* @see MediaSourceEventDispatcher#removeEventListener(Object, Class)
|
||||
*/
|
||||
protected final <T> void removeEventListenerInternal(T eventListener, Class<T> listenerClass) {
|
||||
eventDispatcher.removeEventListener(eventListener, listenerClass);
|
||||
drmEventDispatcher.removeEventListener(eventListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -222,10 +222,12 @@ public abstract class CompositeMediaSource<T> extends BaseMediaSource {
|
|||
implements MediaSourceEventListener, DrmSessionEventListener {
|
||||
|
||||
@UnknownNull private final T id;
|
||||
private EventDispatcher eventDispatcher;
|
||||
private MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher;
|
||||
private DrmSessionEventListener.EventDispatcher drmEventDispatcher;
|
||||
|
||||
public ForwardingEventListener(@UnknownNull T id) {
|
||||
this.eventDispatcher = createEventDispatcher(/* mediaPeriodId= */ null);
|
||||
this.mediaSourceEventDispatcher = createEventDispatcher(/* mediaPeriodId= */ null);
|
||||
this.drmEventDispatcher = createDrmEventDispatcher(/* mediaPeriodId= */ null);
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
|
|
@ -235,8 +237,8 @@ public abstract class CompositeMediaSource<T> extends BaseMediaSource {
|
|||
public void onMediaPeriodCreated(int windowIndex, MediaPeriodId mediaPeriodId) {
|
||||
if (maybeUpdateEventDispatcher(windowIndex, mediaPeriodId)) {
|
||||
if (shouldDispatchCreateOrReleaseEvent(
|
||||
Assertions.checkNotNull(eventDispatcher.mediaPeriodId))) {
|
||||
eventDispatcher.mediaPeriodCreated();
|
||||
Assertions.checkNotNull(mediaSourceEventDispatcher.mediaPeriodId))) {
|
||||
mediaSourceEventDispatcher.mediaPeriodCreated();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -245,8 +247,8 @@ public abstract class CompositeMediaSource<T> extends BaseMediaSource {
|
|||
public void onMediaPeriodReleased(int windowIndex, MediaPeriodId mediaPeriodId) {
|
||||
if (maybeUpdateEventDispatcher(windowIndex, mediaPeriodId)) {
|
||||
if (shouldDispatchCreateOrReleaseEvent(
|
||||
Assertions.checkNotNull(eventDispatcher.mediaPeriodId))) {
|
||||
eventDispatcher.mediaPeriodReleased();
|
||||
Assertions.checkNotNull(mediaSourceEventDispatcher.mediaPeriodId))) {
|
||||
mediaSourceEventDispatcher.mediaPeriodReleased();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -258,7 +260,8 @@ public abstract class CompositeMediaSource<T> extends BaseMediaSource {
|
|||
LoadEventInfo loadEventData,
|
||||
MediaLoadData mediaLoadData) {
|
||||
if (maybeUpdateEventDispatcher(windowIndex, mediaPeriodId)) {
|
||||
eventDispatcher.loadStarted(loadEventData, maybeUpdateMediaLoadData(mediaLoadData));
|
||||
mediaSourceEventDispatcher.loadStarted(
|
||||
loadEventData, maybeUpdateMediaLoadData(mediaLoadData));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -269,7 +272,8 @@ public abstract class CompositeMediaSource<T> extends BaseMediaSource {
|
|||
LoadEventInfo loadEventData,
|
||||
MediaLoadData mediaLoadData) {
|
||||
if (maybeUpdateEventDispatcher(windowIndex, mediaPeriodId)) {
|
||||
eventDispatcher.loadCompleted(loadEventData, maybeUpdateMediaLoadData(mediaLoadData));
|
||||
mediaSourceEventDispatcher.loadCompleted(
|
||||
loadEventData, maybeUpdateMediaLoadData(mediaLoadData));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -280,7 +284,8 @@ public abstract class CompositeMediaSource<T> extends BaseMediaSource {
|
|||
LoadEventInfo loadEventData,
|
||||
MediaLoadData mediaLoadData) {
|
||||
if (maybeUpdateEventDispatcher(windowIndex, mediaPeriodId)) {
|
||||
eventDispatcher.loadCanceled(loadEventData, maybeUpdateMediaLoadData(mediaLoadData));
|
||||
mediaSourceEventDispatcher.loadCanceled(
|
||||
loadEventData, maybeUpdateMediaLoadData(mediaLoadData));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -293,7 +298,7 @@ public abstract class CompositeMediaSource<T> extends BaseMediaSource {
|
|||
IOException error,
|
||||
boolean wasCanceled) {
|
||||
if (maybeUpdateEventDispatcher(windowIndex, mediaPeriodId)) {
|
||||
eventDispatcher.loadError(
|
||||
mediaSourceEventDispatcher.loadError(
|
||||
loadEventData, maybeUpdateMediaLoadData(mediaLoadData), error, wasCanceled);
|
||||
}
|
||||
}
|
||||
|
|
@ -301,7 +306,7 @@ public abstract class CompositeMediaSource<T> extends BaseMediaSource {
|
|||
@Override
|
||||
public void onReadingStarted(int windowIndex, MediaPeriodId mediaPeriodId) {
|
||||
if (maybeUpdateEventDispatcher(windowIndex, mediaPeriodId)) {
|
||||
eventDispatcher.readingStarted();
|
||||
mediaSourceEventDispatcher.readingStarted();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -309,7 +314,7 @@ public abstract class CompositeMediaSource<T> extends BaseMediaSource {
|
|||
public void onUpstreamDiscarded(
|
||||
int windowIndex, @Nullable MediaPeriodId mediaPeriodId, MediaLoadData mediaLoadData) {
|
||||
if (maybeUpdateEventDispatcher(windowIndex, mediaPeriodId)) {
|
||||
eventDispatcher.upstreamDiscarded(maybeUpdateMediaLoadData(mediaLoadData));
|
||||
mediaSourceEventDispatcher.upstreamDiscarded(maybeUpdateMediaLoadData(mediaLoadData));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -317,7 +322,7 @@ public abstract class CompositeMediaSource<T> extends BaseMediaSource {
|
|||
public void onDownstreamFormatChanged(
|
||||
int windowIndex, @Nullable MediaPeriodId mediaPeriodId, MediaLoadData mediaLoadData) {
|
||||
if (maybeUpdateEventDispatcher(windowIndex, mediaPeriodId)) {
|
||||
eventDispatcher.downstreamFormatChanged(maybeUpdateMediaLoadData(mediaLoadData));
|
||||
mediaSourceEventDispatcher.downstreamFormatChanged(maybeUpdateMediaLoadData(mediaLoadData));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -326,16 +331,14 @@ public abstract class CompositeMediaSource<T> extends BaseMediaSource {
|
|||
@Override
|
||||
public void onDrmSessionAcquired(int windowIndex, @Nullable MediaPeriodId mediaPeriodId) {
|
||||
if (maybeUpdateEventDispatcher(windowIndex, mediaPeriodId)) {
|
||||
eventDispatcher.dispatch(
|
||||
DrmSessionEventListener::onDrmSessionAcquired, DrmSessionEventListener.class);
|
||||
drmEventDispatcher.drmSessionAcquired();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDrmKeysLoaded(int windowIndex, @Nullable MediaPeriodId mediaPeriodId) {
|
||||
if (maybeUpdateEventDispatcher(windowIndex, mediaPeriodId)) {
|
||||
eventDispatcher.dispatch(
|
||||
DrmSessionEventListener::onDrmKeysLoaded, DrmSessionEventListener.class);
|
||||
drmEventDispatcher.drmKeysLoaded();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -343,34 +346,28 @@ public abstract class CompositeMediaSource<T> extends BaseMediaSource {
|
|||
public void onDrmSessionManagerError(
|
||||
int windowIndex, @Nullable MediaPeriodId mediaPeriodId, Exception error) {
|
||||
if (maybeUpdateEventDispatcher(windowIndex, mediaPeriodId)) {
|
||||
eventDispatcher.dispatch(
|
||||
(listener, innerWindowIndex, innerMediaPeriodId) ->
|
||||
listener.onDrmSessionManagerError(innerWindowIndex, innerMediaPeriodId, error),
|
||||
DrmSessionEventListener.class);
|
||||
drmEventDispatcher.drmSessionManagerError(error);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDrmKeysRestored(int windowIndex, @Nullable MediaPeriodId mediaPeriodId) {
|
||||
if (maybeUpdateEventDispatcher(windowIndex, mediaPeriodId)) {
|
||||
eventDispatcher.dispatch(
|
||||
DrmSessionEventListener::onDrmKeysRestored, DrmSessionEventListener.class);
|
||||
drmEventDispatcher.drmKeysRestored();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDrmKeysRemoved(int windowIndex, @Nullable MediaPeriodId mediaPeriodId) {
|
||||
if (maybeUpdateEventDispatcher(windowIndex, mediaPeriodId)) {
|
||||
eventDispatcher.dispatch(
|
||||
DrmSessionEventListener::onDrmKeysRemoved, DrmSessionEventListener.class);
|
||||
drmEventDispatcher.drmKeysRemoved();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDrmSessionReleased(int windowIndex, @Nullable MediaPeriodId mediaPeriodId) {
|
||||
if (maybeUpdateEventDispatcher(windowIndex, mediaPeriodId)) {
|
||||
eventDispatcher.dispatch(
|
||||
DrmSessionEventListener::onDrmSessionReleased, DrmSessionEventListener.class);
|
||||
drmEventDispatcher.drmSessionReleased();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -386,11 +383,15 @@ public abstract class CompositeMediaSource<T> extends BaseMediaSource {
|
|||
}
|
||||
}
|
||||
int windowIndex = getWindowIndexForChildWindowIndex(id, childWindowIndex);
|
||||
if (eventDispatcher.windowIndex != windowIndex
|
||||
|| !Util.areEqual(eventDispatcher.mediaPeriodId, mediaPeriodId)) {
|
||||
eventDispatcher =
|
||||
if (mediaSourceEventDispatcher.windowIndex != windowIndex
|
||||
|| !Util.areEqual(mediaSourceEventDispatcher.mediaPeriodId, mediaPeriodId)) {
|
||||
mediaSourceEventDispatcher =
|
||||
createEventDispatcher(windowIndex, mediaPeriodId, /* mediaTimeOffsetMs= */ 0);
|
||||
}
|
||||
if (drmEventDispatcher.windowIndex != windowIndex
|
||||
|| !Util.areEqual(drmEventDispatcher.mediaPeriodId, mediaPeriodId)) {
|
||||
drmEventDispatcher = createDrmEventDispatcher(windowIndex, mediaPeriodId);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -15,15 +15,17 @@
|
|||
*/
|
||||
package com.google.android.exoplayer2.source;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import androidx.annotation.CheckResult;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.Player;
|
||||
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.CopyOnWriteMultiset;
|
||||
import com.google.android.exoplayer2.util.MediaSourceEventDispatcher;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
/** Interface for callbacks to be notified of {@link MediaSource} events. */
|
||||
public interface MediaSourceEventListener {
|
||||
|
|
@ -160,42 +162,101 @@ public interface MediaSourceEventListener {
|
|||
default void onDownstreamFormatChanged(
|
||||
int windowIndex, @Nullable MediaPeriodId mediaPeriodId, MediaLoadData mediaLoadData) {}
|
||||
|
||||
/** @deprecated Use {@link MediaSourceEventDispatcher} directly instead. */
|
||||
@Deprecated
|
||||
final class EventDispatcher extends MediaSourceEventDispatcher {
|
||||
/** Dispatches events to {@link MediaSourceEventListener MediaSourceEventListeners}. */
|
||||
class EventDispatcher {
|
||||
|
||||
/** The timeline window index reported with the events. */
|
||||
public final int windowIndex;
|
||||
/** The {@link MediaPeriodId} reported with the events. */
|
||||
@Nullable public final MediaPeriodId mediaPeriodId;
|
||||
|
||||
private final CopyOnWriteArrayList<ListenerAndHandler> listenerAndHandlers;
|
||||
private final long mediaTimeOffsetMs;
|
||||
|
||||
/** Creates an event dispatcher. */
|
||||
public EventDispatcher() {
|
||||
super();
|
||||
this(
|
||||
/* listenerAndHandlers= */ new CopyOnWriteArrayList<>(),
|
||||
/* windowIndex= */ 0,
|
||||
/* mediaPeriodId= */ null,
|
||||
/* mediaTimeOffsetMs= */ 0);
|
||||
}
|
||||
|
||||
private EventDispatcher(
|
||||
CopyOnWriteMultiset<ListenerInfo> listeners,
|
||||
CopyOnWriteArrayList<ListenerAndHandler> listenerAndHandlers,
|
||||
int windowIndex,
|
||||
@Nullable MediaPeriodId mediaPeriodId,
|
||||
long mediaTimeOffsetMs) {
|
||||
super(listeners, windowIndex, mediaPeriodId, mediaTimeOffsetMs);
|
||||
this.listenerAndHandlers = listenerAndHandlers;
|
||||
this.windowIndex = windowIndex;
|
||||
this.mediaPeriodId = mediaPeriodId;
|
||||
this.mediaTimeOffsetMs = mediaTimeOffsetMs;
|
||||
}
|
||||
|
||||
@Override
|
||||
/**
|
||||
* Creates a view of the event dispatcher with pre-configured window index, media period id, and
|
||||
* media time offset.
|
||||
*
|
||||
* @param windowIndex The timeline window index to be reported with the events.
|
||||
* @param mediaPeriodId The {@link MediaPeriodId} to be reported with the events.
|
||||
* @param mediaTimeOffsetMs The offset to be added to all media times, in milliseconds.
|
||||
* @return A view of the event dispatcher with the pre-configured parameters.
|
||||
*/
|
||||
@CheckResult
|
||||
public EventDispatcher withParameters(
|
||||
int windowIndex, @Nullable MediaPeriodId mediaPeriodId, long mediaTimeOffsetMs) {
|
||||
return new EventDispatcher(listenerInfos, windowIndex, mediaPeriodId, mediaTimeOffsetMs);
|
||||
return new EventDispatcher(
|
||||
listenerAndHandlers, windowIndex, mediaPeriodId, mediaTimeOffsetMs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a listener to the event dispatcher.
|
||||
*
|
||||
* @param handler A handler on the which listener events will be posted.
|
||||
* @param eventListener The listener to be added.
|
||||
*/
|
||||
public void addEventListener(Handler handler, MediaSourceEventListener eventListener) {
|
||||
Assertions.checkNotNull(handler);
|
||||
Assertions.checkNotNull(eventListener);
|
||||
listenerAndHandlers.add(new ListenerAndHandler(handler, eventListener));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a listener from the event dispatcher.
|
||||
*
|
||||
* @param eventListener The listener to be removed.
|
||||
*/
|
||||
public void removeEventListener(MediaSourceEventListener eventListener) {
|
||||
for (ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
|
||||
if (listenerAndHandler.listener == eventListener) {
|
||||
listenerAndHandlers.remove(listenerAndHandler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Dispatches {@link #onMediaPeriodCreated(int, MediaPeriodId)}. */
|
||||
public void mediaPeriodCreated() {
|
||||
dispatch(
|
||||
(listener, windowIndex, mediaPeriodId) ->
|
||||
listener.onMediaPeriodCreated(windowIndex, Assertions.checkNotNull(mediaPeriodId)),
|
||||
MediaSourceEventListener.class);
|
||||
MediaPeriodId mediaPeriodId = Assertions.checkNotNull(this.mediaPeriodId);
|
||||
for (ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
|
||||
MediaSourceEventListener listener = listenerAndHandler.listener;
|
||||
postOrRun(
|
||||
listenerAndHandler.handler,
|
||||
() -> listener.onMediaPeriodCreated(windowIndex, mediaPeriodId));
|
||||
}
|
||||
}
|
||||
|
||||
/** Dispatches {@link #onMediaPeriodReleased(int, MediaPeriodId)}. */
|
||||
public void mediaPeriodReleased() {
|
||||
dispatch(
|
||||
(listener, windowIndex, mediaPeriodId) ->
|
||||
listener.onMediaPeriodReleased(windowIndex, Assertions.checkNotNull(mediaPeriodId)),
|
||||
MediaSourceEventListener.class);
|
||||
MediaPeriodId mediaPeriodId = Assertions.checkNotNull(this.mediaPeriodId);
|
||||
for (ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
|
||||
MediaSourceEventListener listener = listenerAndHandler.listener;
|
||||
postOrRun(
|
||||
listenerAndHandler.handler,
|
||||
() -> listener.onMediaPeriodReleased(windowIndex, mediaPeriodId));
|
||||
}
|
||||
}
|
||||
|
||||
/** Dispatches {@link #onLoadStarted(int, MediaPeriodId, LoadEventInfo, MediaLoadData)}. */
|
||||
public void loadStarted(LoadEventInfo loadEventInfo, int dataType) {
|
||||
loadStarted(
|
||||
loadEventInfo,
|
||||
|
|
@ -208,6 +269,7 @@ public interface MediaSourceEventListener {
|
|||
/* mediaEndTimeUs= */ C.TIME_UNSET);
|
||||
}
|
||||
|
||||
/** Dispatches {@link #onLoadStarted(int, MediaPeriodId, LoadEventInfo, MediaLoadData)}. */
|
||||
public void loadStarted(
|
||||
LoadEventInfo loadEventInfo,
|
||||
int dataType,
|
||||
|
|
@ -229,13 +291,17 @@ public interface MediaSourceEventListener {
|
|||
adjustMediaTime(mediaEndTimeUs)));
|
||||
}
|
||||
|
||||
/** Dispatches {@link #onLoadStarted(int, MediaPeriodId, LoadEventInfo, MediaLoadData)}. */
|
||||
public void loadStarted(LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData) {
|
||||
dispatch(
|
||||
(listener, windowIndex, mediaPeriodId) ->
|
||||
listener.onLoadStarted(windowIndex, mediaPeriodId, loadEventInfo, mediaLoadData),
|
||||
MediaSourceEventListener.class);
|
||||
for (ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
|
||||
MediaSourceEventListener listener = listenerAndHandler.listener;
|
||||
postOrRun(
|
||||
listenerAndHandler.handler,
|
||||
() -> listener.onLoadStarted(windowIndex, mediaPeriodId, loadEventInfo, mediaLoadData));
|
||||
}
|
||||
}
|
||||
|
||||
/** Dispatches {@link #onLoadCompleted(int, MediaPeriodId, LoadEventInfo, MediaLoadData)}. */
|
||||
public void loadCompleted(LoadEventInfo loadEventInfo, int dataType) {
|
||||
loadCompleted(
|
||||
loadEventInfo,
|
||||
|
|
@ -248,6 +314,7 @@ public interface MediaSourceEventListener {
|
|||
/* mediaEndTimeUs= */ C.TIME_UNSET);
|
||||
}
|
||||
|
||||
/** Dispatches {@link #onLoadCompleted(int, MediaPeriodId, LoadEventInfo, MediaLoadData)}. */
|
||||
public void loadCompleted(
|
||||
LoadEventInfo loadEventInfo,
|
||||
int dataType,
|
||||
|
|
@ -269,13 +336,18 @@ public interface MediaSourceEventListener {
|
|||
adjustMediaTime(mediaEndTimeUs)));
|
||||
}
|
||||
|
||||
/** Dispatches {@link #onLoadCompleted(int, MediaPeriodId, LoadEventInfo, MediaLoadData)}. */
|
||||
public void loadCompleted(LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData) {
|
||||
dispatch(
|
||||
(listener, windowIndex, mediaPeriodId) ->
|
||||
listener.onLoadCompleted(windowIndex, mediaPeriodId, loadEventInfo, mediaLoadData),
|
||||
MediaSourceEventListener.class);
|
||||
for (ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
|
||||
MediaSourceEventListener listener = listenerAndHandler.listener;
|
||||
postOrRun(
|
||||
listenerAndHandler.handler,
|
||||
() ->
|
||||
listener.onLoadCompleted(windowIndex, mediaPeriodId, loadEventInfo, mediaLoadData));
|
||||
}
|
||||
}
|
||||
|
||||
/** Dispatches {@link #onLoadCanceled(int, MediaPeriodId, LoadEventInfo, MediaLoadData)}. */
|
||||
public void loadCanceled(LoadEventInfo loadEventInfo, int dataType) {
|
||||
loadCanceled(
|
||||
loadEventInfo,
|
||||
|
|
@ -288,6 +360,7 @@ public interface MediaSourceEventListener {
|
|||
/* mediaEndTimeUs= */ C.TIME_UNSET);
|
||||
}
|
||||
|
||||
/** Dispatches {@link #onLoadCanceled(int, MediaPeriodId, LoadEventInfo, MediaLoadData)}. */
|
||||
public void loadCanceled(
|
||||
LoadEventInfo loadEventInfo,
|
||||
int dataType,
|
||||
|
|
@ -309,13 +382,21 @@ public interface MediaSourceEventListener {
|
|||
adjustMediaTime(mediaEndTimeUs)));
|
||||
}
|
||||
|
||||
/** Dispatches {@link #onLoadCanceled(int, MediaPeriodId, LoadEventInfo, MediaLoadData)}. */
|
||||
public void loadCanceled(LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData) {
|
||||
dispatch(
|
||||
(listener, windowIndex, mediaPeriodId) ->
|
||||
listener.onLoadCanceled(windowIndex, mediaPeriodId, loadEventInfo, mediaLoadData),
|
||||
MediaSourceEventListener.class);
|
||||
for (ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
|
||||
MediaSourceEventListener listener = listenerAndHandler.listener;
|
||||
postOrRun(
|
||||
listenerAndHandler.handler,
|
||||
() ->
|
||||
listener.onLoadCanceled(windowIndex, mediaPeriodId, loadEventInfo, mediaLoadData));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches {@link #onLoadError(int, MediaPeriodId, LoadEventInfo, MediaLoadData, IOException,
|
||||
* boolean)}.
|
||||
*/
|
||||
public void loadError(
|
||||
LoadEventInfo loadEventInfo, int dataType, IOException error, boolean wasCanceled) {
|
||||
loadError(
|
||||
|
|
@ -331,6 +412,10 @@ public interface MediaSourceEventListener {
|
|||
wasCanceled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches {@link #onLoadError(int, MediaPeriodId, LoadEventInfo, MediaLoadData, IOException,
|
||||
* boolean)}.
|
||||
*/
|
||||
public void loadError(
|
||||
LoadEventInfo loadEventInfo,
|
||||
int dataType,
|
||||
|
|
@ -356,25 +441,37 @@ public interface MediaSourceEventListener {
|
|||
wasCanceled);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches {@link #onLoadError(int, MediaPeriodId, LoadEventInfo, MediaLoadData, IOException,
|
||||
* boolean)}.
|
||||
*/
|
||||
public void loadError(
|
||||
LoadEventInfo loadEventInfo,
|
||||
MediaLoadData mediaLoadData,
|
||||
IOException error,
|
||||
boolean wasCanceled) {
|
||||
dispatch(
|
||||
(listener, windowIndex, mediaPeriodId) ->
|
||||
listener.onLoadError(
|
||||
windowIndex, mediaPeriodId, loadEventInfo, mediaLoadData, error, wasCanceled),
|
||||
MediaSourceEventListener.class);
|
||||
for (ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
|
||||
MediaSourceEventListener listener = listenerAndHandler.listener;
|
||||
postOrRun(
|
||||
listenerAndHandler.handler,
|
||||
() ->
|
||||
listener.onLoadError(
|
||||
windowIndex, mediaPeriodId, loadEventInfo, mediaLoadData, error, wasCanceled));
|
||||
}
|
||||
}
|
||||
|
||||
/** Dispatches {@link #onReadingStarted(int, MediaPeriodId)}. */
|
||||
public void readingStarted() {
|
||||
dispatch(
|
||||
(listener, windowIndex, mediaPeriodId) ->
|
||||
listener.onReadingStarted(windowIndex, Assertions.checkNotNull(mediaPeriodId)),
|
||||
MediaSourceEventListener.class);
|
||||
MediaPeriodId mediaPeriodId = Assertions.checkNotNull(this.mediaPeriodId);
|
||||
for (ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
|
||||
MediaSourceEventListener listener = listenerAndHandler.listener;
|
||||
postOrRun(
|
||||
listenerAndHandler.handler,
|
||||
() -> listener.onReadingStarted(windowIndex, mediaPeriodId));
|
||||
}
|
||||
}
|
||||
|
||||
/** Dispatches {@link #onUpstreamDiscarded(int, MediaPeriodId, MediaLoadData)}. */
|
||||
public void upstreamDiscarded(int trackType, long mediaStartTimeUs, long mediaEndTimeUs) {
|
||||
upstreamDiscarded(
|
||||
new MediaLoadData(
|
||||
|
|
@ -387,14 +484,18 @@ public interface MediaSourceEventListener {
|
|||
adjustMediaTime(mediaEndTimeUs)));
|
||||
}
|
||||
|
||||
/** Dispatches {@link #onUpstreamDiscarded(int, MediaPeriodId, MediaLoadData)}. */
|
||||
public void upstreamDiscarded(MediaLoadData mediaLoadData) {
|
||||
dispatch(
|
||||
(listener, windowIndex, mediaPeriodId) ->
|
||||
listener.onUpstreamDiscarded(
|
||||
windowIndex, Assertions.checkNotNull(mediaPeriodId), mediaLoadData),
|
||||
MediaSourceEventListener.class);
|
||||
MediaPeriodId mediaPeriodId = Assertions.checkNotNull(this.mediaPeriodId);
|
||||
for (ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
|
||||
MediaSourceEventListener listener = listenerAndHandler.listener;
|
||||
postOrRun(
|
||||
listenerAndHandler.handler,
|
||||
() -> listener.onUpstreamDiscarded(windowIndex, mediaPeriodId, mediaLoadData));
|
||||
}
|
||||
}
|
||||
|
||||
/** Dispatches {@link #onDownstreamFormatChanged(int, MediaPeriodId, MediaLoadData)}. */
|
||||
public void downstreamFormatChanged(
|
||||
int trackType,
|
||||
@Nullable Format trackFormat,
|
||||
|
|
@ -412,15 +513,38 @@ public interface MediaSourceEventListener {
|
|||
/* mediaEndTimeMs= */ C.TIME_UNSET));
|
||||
}
|
||||
|
||||
/** Dispatches {@link #onDownstreamFormatChanged(int, MediaPeriodId, MediaLoadData)}. */
|
||||
public void downstreamFormatChanged(MediaLoadData mediaLoadData) {
|
||||
dispatch(
|
||||
(listener, windowIndex, mediaPeriodId) ->
|
||||
listener.onDownstreamFormatChanged(windowIndex, mediaPeriodId, mediaLoadData),
|
||||
MediaSourceEventListener.class);
|
||||
for (ListenerAndHandler listenerAndHandler : listenerAndHandlers) {
|
||||
MediaSourceEventListener listener = listenerAndHandler.listener;
|
||||
postOrRun(
|
||||
listenerAndHandler.handler,
|
||||
() -> listener.onDownstreamFormatChanged(windowIndex, mediaPeriodId, mediaLoadData));
|
||||
}
|
||||
}
|
||||
|
||||
private long adjustMediaTime(long mediaTimeUs) {
|
||||
return adjustMediaTime(mediaTimeUs, mediaTimeOffsetMs);
|
||||
long mediaTimeMs = C.usToMs(mediaTimeUs);
|
||||
return mediaTimeMs == C.TIME_UNSET ? C.TIME_UNSET : mediaTimeOffsetMs + mediaTimeMs;
|
||||
}
|
||||
|
||||
private static void postOrRun(Handler handler, Runnable runnable) {
|
||||
if (handler.getLooper() == Looper.myLooper()) {
|
||||
runnable.run();
|
||||
} else {
|
||||
handler.post(runnable);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class ListenerAndHandler {
|
||||
|
||||
public Handler handler;
|
||||
public MediaSourceEventListener listener;
|
||||
|
||||
public ListenerAndHandler(Handler handler, MediaSourceEventListener listener) {
|
||||
this.handler = handler;
|
||||
this.listener = listener;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import com.google.android.exoplayer2.FormatHolder;
|
|||
import com.google.android.exoplayer2.ParserException;
|
||||
import com.google.android.exoplayer2.SeekParameters;
|
||||
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionEventListener;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.extractor.Extractor;
|
||||
import com.google.android.exoplayer2.extractor.ExtractorOutput;
|
||||
|
|
@ -35,7 +36,6 @@ import com.google.android.exoplayer2.extractor.SeekMap.Unseekable;
|
|||
import com.google.android.exoplayer2.extractor.TrackOutput;
|
||||
import com.google.android.exoplayer2.metadata.Metadata;
|
||||
import com.google.android.exoplayer2.metadata.icy.IcyHeaders;
|
||||
import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher;
|
||||
import com.google.android.exoplayer2.source.SampleQueue.UpstreamFormatChangedListener;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelection;
|
||||
import com.google.android.exoplayer2.upstream.Allocator;
|
||||
|
|
@ -101,7 +101,8 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||
private final DataSource dataSource;
|
||||
private final DrmSessionManager drmSessionManager;
|
||||
private final LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
||||
private final EventDispatcher eventDispatcher;
|
||||
private final MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher;
|
||||
private final DrmSessionEventListener.EventDispatcher drmEventDispatcher;
|
||||
private final Listener listener;
|
||||
private final Allocator allocator;
|
||||
@Nullable private final String customCacheKey;
|
||||
|
|
@ -145,8 +146,11 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||
* @param uri The {@link Uri} of the media stream.
|
||||
* @param dataSource The data source to read the media.
|
||||
* @param extractorsFactory The {@link ExtractorsFactory} to use to read the data source.
|
||||
* @param drmSessionManager A {@link DrmSessionManager} to allow DRM interactions.
|
||||
* @param drmEventDispatcher A dispatcher to notify of {@link DrmSessionEventListener} events.
|
||||
* @param loadErrorHandlingPolicy The {@link LoadErrorHandlingPolicy}.
|
||||
* @param eventDispatcher A dispatcher to notify of events.
|
||||
* @param mediaSourceEventDispatcher A dispatcher to notify of {@link MediaSourceEventListener}
|
||||
* events.
|
||||
* @param listener A listener to notify when information about the period changes.
|
||||
* @param allocator An {@link Allocator} from which to obtain media buffer allocations.
|
||||
* @param customCacheKey A custom key that uniquely identifies the original stream. Used for cache
|
||||
|
|
@ -164,8 +168,9 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||
DataSource dataSource,
|
||||
ExtractorsFactory extractorsFactory,
|
||||
DrmSessionManager drmSessionManager,
|
||||
DrmSessionEventListener.EventDispatcher drmEventDispatcher,
|
||||
LoadErrorHandlingPolicy loadErrorHandlingPolicy,
|
||||
EventDispatcher eventDispatcher,
|
||||
MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher,
|
||||
Listener listener,
|
||||
Allocator allocator,
|
||||
@Nullable String customCacheKey,
|
||||
|
|
@ -173,8 +178,9 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||
this.uri = uri;
|
||||
this.dataSource = dataSource;
|
||||
this.drmSessionManager = drmSessionManager;
|
||||
this.drmEventDispatcher = drmEventDispatcher;
|
||||
this.loadErrorHandlingPolicy = loadErrorHandlingPolicy;
|
||||
this.eventDispatcher = eventDispatcher;
|
||||
this.mediaSourceEventDispatcher = mediaSourceEventDispatcher;
|
||||
this.listener = listener;
|
||||
this.allocator = allocator;
|
||||
this.customCacheKey = customCacheKey;
|
||||
|
|
@ -199,7 +205,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||
length = C.LENGTH_UNSET;
|
||||
durationUs = C.TIME_UNSET;
|
||||
dataType = C.DATA_TYPE_MEDIA;
|
||||
eventDispatcher.mediaPeriodCreated();
|
||||
mediaSourceEventDispatcher.mediaPeriodCreated();
|
||||
}
|
||||
|
||||
public void release() {
|
||||
|
|
@ -214,7 +220,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||
handler.removeCallbacksAndMessages(null);
|
||||
callback = null;
|
||||
released = true;
|
||||
eventDispatcher.mediaPeriodReleased();
|
||||
mediaSourceEventDispatcher.mediaPeriodReleased();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -369,7 +375,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||
@Override
|
||||
public long readDiscontinuity() {
|
||||
if (!notifiedReadingStarted) {
|
||||
eventDispatcher.readingStarted();
|
||||
mediaSourceEventDispatcher.readingStarted();
|
||||
notifiedReadingStarted = true;
|
||||
}
|
||||
if (notifyDiscontinuity
|
||||
|
|
@ -510,7 +516,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||
boolean[] trackNotifiedDownstreamFormats = trackState.trackNotifiedDownstreamFormats;
|
||||
if (!trackNotifiedDownstreamFormats[track]) {
|
||||
Format trackFormat = trackState.tracks.get(track).getFormat(/* index= */ 0);
|
||||
eventDispatcher.downstreamFormatChanged(
|
||||
mediaSourceEventDispatcher.downstreamFormatChanged(
|
||||
MimeTypes.getTrackType(trackFormat.sampleMimeType),
|
||||
trackFormat,
|
||||
C.SELECTION_REASON_UNKNOWN,
|
||||
|
|
@ -566,7 +572,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||
loadDurationMs,
|
||||
dataSource.getBytesRead());
|
||||
loadErrorHandlingPolicy.onLoadTaskConcluded(loadable.loadTaskId);
|
||||
eventDispatcher.loadCompleted(
|
||||
mediaSourceEventDispatcher.loadCompleted(
|
||||
loadEventInfo,
|
||||
C.DATA_TYPE_MEDIA,
|
||||
C.TRACK_TYPE_UNKNOWN,
|
||||
|
|
@ -594,7 +600,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||
loadDurationMs,
|
||||
dataSource.getBytesRead());
|
||||
loadErrorHandlingPolicy.onLoadTaskConcluded(loadable.loadTaskId);
|
||||
eventDispatcher.loadCanceled(
|
||||
mediaSourceEventDispatcher.loadCanceled(
|
||||
loadEventInfo,
|
||||
C.DATA_TYPE_MEDIA,
|
||||
C.TRACK_TYPE_UNKNOWN,
|
||||
|
|
@ -657,7 +663,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||
}
|
||||
|
||||
boolean wasCanceled = !loadErrorAction.isRetry();
|
||||
eventDispatcher.loadError(
|
||||
mediaSourceEventDispatcher.loadError(
|
||||
loadEventInfo,
|
||||
C.DATA_TYPE_MEDIA,
|
||||
C.TRACK_TYPE_UNKNOWN,
|
||||
|
|
@ -719,7 +725,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||
allocator,
|
||||
/* playbackLooper= */ handler.getLooper(),
|
||||
drmSessionManager,
|
||||
eventDispatcher);
|
||||
drmEventDispatcher);
|
||||
trackOutput.setUpstreamFormatChangeListener(this);
|
||||
@NullableType
|
||||
TrackId[] sampleQueueTrackIds = Arrays.copyOf(this.sampleQueueTrackIds, trackCount + 1);
|
||||
|
|
@ -824,7 +830,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||
loader.startLoading(
|
||||
loadable, this, loadErrorHandlingPolicy.getMinimumLoadableRetryCount(dataType));
|
||||
DataSpec dataSpec = loadable.dataSpec;
|
||||
eventDispatcher.loadStarted(
|
||||
mediaSourceEventDispatcher.loadStarted(
|
||||
new LoadEventInfo(loadable.loadTaskId, dataSpec, elapsedRealtimeMs),
|
||||
C.DATA_TYPE_MEDIA,
|
||||
C.TRACK_TYPE_UNKNOWN,
|
||||
|
|
|
|||
|
|
@ -283,6 +283,7 @@ public final class ProgressiveMediaSource extends BaseMediaSource
|
|||
dataSource,
|
||||
extractorsFactory,
|
||||
drmSessionManager,
|
||||
createDrmEventDispatcher(id),
|
||||
loadableLoadErrorHandlingPolicy,
|
||||
createEventDispatcher(id),
|
||||
this,
|
||||
|
|
|
|||
|
|
@ -26,12 +26,12 @@ import com.google.android.exoplayer2.FormatHolder;
|
|||
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
|
||||
import com.google.android.exoplayer2.drm.DrmInitData;
|
||||
import com.google.android.exoplayer2.drm.DrmSession;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionEventListener;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.extractor.TrackOutput;
|
||||
import com.google.android.exoplayer2.upstream.Allocator;
|
||||
import com.google.android.exoplayer2.upstream.DataReader;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.MediaSourceEventDispatcher;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
|
|
@ -59,7 +59,7 @@ public class SampleQueue implements TrackOutput {
|
|||
private final SampleExtrasHolder extrasHolder;
|
||||
private final Looper playbackLooper;
|
||||
private final DrmSessionManager drmSessionManager;
|
||||
private final MediaSourceEventDispatcher eventDispatcher;
|
||||
private final DrmSessionEventListener.EventDispatcher drmEventDispatcher;
|
||||
@Nullable private UpstreamFormatChangedListener upstreamFormatChangeListener;
|
||||
|
||||
@Nullable private Format downstreamFormat;
|
||||
|
|
@ -103,17 +103,17 @@ public class SampleQueue implements TrackOutput {
|
|||
* @param playbackLooper The looper associated with the media playback thread.
|
||||
* @param drmSessionManager The {@link DrmSessionManager} to obtain {@link DrmSession DrmSessions}
|
||||
* from. The created instance does not take ownership of this {@link DrmSessionManager}.
|
||||
* @param eventDispatcher A {@link MediaSourceEventDispatcher} to notify of events related to this
|
||||
* SampleQueue.
|
||||
* @param drmEventDispatcher A {@link DrmSessionEventListener.EventDispatcher} to notify of events
|
||||
* related to this SampleQueue.
|
||||
*/
|
||||
public SampleQueue(
|
||||
Allocator allocator,
|
||||
Looper playbackLooper,
|
||||
DrmSessionManager drmSessionManager,
|
||||
MediaSourceEventDispatcher eventDispatcher) {
|
||||
DrmSessionEventListener.EventDispatcher drmEventDispatcher) {
|
||||
this.playbackLooper = playbackLooper;
|
||||
this.drmSessionManager = drmSessionManager;
|
||||
this.eventDispatcher = eventDispatcher;
|
||||
this.drmEventDispatcher = drmEventDispatcher;
|
||||
sampleDataQueue = new SampleDataQueue(allocator);
|
||||
extrasHolder = new SampleExtrasHolder();
|
||||
capacity = SAMPLE_CAPACITY_INCREMENT;
|
||||
|
|
@ -691,7 +691,7 @@ public class SampleQueue implements TrackOutput {
|
|||
|
||||
private void releaseDrmSessionReferences() {
|
||||
if (currentDrmSession != null) {
|
||||
currentDrmSession.release(eventDispatcher);
|
||||
currentDrmSession.release(drmEventDispatcher);
|
||||
currentDrmSession = null;
|
||||
// Clear downstream format to avoid violating the assumption that downstreamFormat.drmInitData
|
||||
// != null implies currentSession != null
|
||||
|
|
@ -826,13 +826,13 @@ public class SampleQueue implements TrackOutput {
|
|||
@Nullable DrmSession previousSession = currentDrmSession;
|
||||
currentDrmSession =
|
||||
newDrmInitData != null
|
||||
? drmSessionManager.acquireSession(playbackLooper, eventDispatcher, newDrmInitData)
|
||||
? drmSessionManager.acquireSession(playbackLooper, drmEventDispatcher, newDrmInitData)
|
||||
: drmSessionManager.acquirePlaceholderSession(
|
||||
playbackLooper, MimeTypes.getTrackType(newFormat.sampleMimeType));
|
||||
outputFormatHolder.drmSession = currentDrmSession;
|
||||
|
||||
if (previousSession != null) {
|
||||
previousSession.release(eventDispatcher);
|
||||
previousSession.release(drmEventDispatcher);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,10 +23,11 @@ import com.google.android.exoplayer2.FormatHolder;
|
|||
import com.google.android.exoplayer2.SeekParameters;
|
||||
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
|
||||
import com.google.android.exoplayer2.drm.DrmSession;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionEventListener;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.source.LoadEventInfo;
|
||||
import com.google.android.exoplayer2.source.MediaLoadData;
|
||||
import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher;
|
||||
import com.google.android.exoplayer2.source.MediaSourceEventListener;
|
||||
import com.google.android.exoplayer2.source.SampleQueue;
|
||||
import com.google.android.exoplayer2.source.SampleStream;
|
||||
import com.google.android.exoplayer2.source.SequenceableLoader;
|
||||
|
|
@ -71,7 +72,7 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
|
|||
private final boolean[] embeddedTracksSelected;
|
||||
private final T chunkSource;
|
||||
private final SequenceableLoader.Callback<ChunkSampleStream<T>> callback;
|
||||
private final EventDispatcher eventDispatcher;
|
||||
private final MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher;
|
||||
private final LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
||||
private final Loader loader;
|
||||
private final ChunkHolder nextChunkHolder;
|
||||
|
|
@ -102,8 +103,10 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
|
|||
* @param positionUs The position from which to start loading media.
|
||||
* @param drmSessionManager The {@link DrmSessionManager} to obtain {@link DrmSession DrmSessions}
|
||||
* from.
|
||||
* @param drmEventDispatcher A dispatcher to notify of {@link DrmSessionEventListener} events.
|
||||
* @param loadErrorHandlingPolicy The {@link LoadErrorHandlingPolicy}.
|
||||
* @param eventDispatcher A dispatcher to notify of events.
|
||||
* @param mediaSourceEventDispatcher A dispatcher to notify of {@link MediaSourceEventListener}
|
||||
* events.
|
||||
*/
|
||||
public ChunkSampleStream(
|
||||
int primaryTrackType,
|
||||
|
|
@ -114,14 +117,15 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
|
|||
Allocator allocator,
|
||||
long positionUs,
|
||||
DrmSessionManager drmSessionManager,
|
||||
DrmSessionEventListener.EventDispatcher drmEventDispatcher,
|
||||
LoadErrorHandlingPolicy loadErrorHandlingPolicy,
|
||||
EventDispatcher eventDispatcher) {
|
||||
MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher) {
|
||||
this.primaryTrackType = primaryTrackType;
|
||||
this.embeddedTrackTypes = embeddedTrackTypes == null ? new int[0] : embeddedTrackTypes;
|
||||
this.embeddedTrackFormats = embeddedTrackFormats == null ? new Format[0] : embeddedTrackFormats;
|
||||
this.chunkSource = chunkSource;
|
||||
this.callback = callback;
|
||||
this.eventDispatcher = eventDispatcher;
|
||||
this.mediaSourceEventDispatcher = mediaSourceEventDispatcher;
|
||||
this.loadErrorHandlingPolicy = loadErrorHandlingPolicy;
|
||||
loader = new Loader("Loader:ChunkSampleStream");
|
||||
nextChunkHolder = new ChunkHolder();
|
||||
|
|
@ -139,7 +143,7 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
|
|||
allocator,
|
||||
/* playbackLooper= */ Assertions.checkNotNull(Looper.myLooper()),
|
||||
drmSessionManager,
|
||||
eventDispatcher);
|
||||
drmEventDispatcher);
|
||||
trackTypes[0] = primaryTrackType;
|
||||
sampleQueues[0] = primarySampleQueue;
|
||||
|
||||
|
|
@ -149,7 +153,7 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
|
|||
allocator,
|
||||
/* playbackLooper= */ Assertions.checkNotNull(Looper.myLooper()),
|
||||
DrmSessionManager.getDummyDrmSessionManager(),
|
||||
eventDispatcher);
|
||||
drmEventDispatcher);
|
||||
embeddedSampleQueues[i] = sampleQueue;
|
||||
sampleQueues[i + 1] = sampleQueue;
|
||||
trackTypes[i + 1] = this.embeddedTrackTypes[i];
|
||||
|
|
@ -413,7 +417,7 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
|
|||
loadDurationMs,
|
||||
loadable.bytesLoaded());
|
||||
loadErrorHandlingPolicy.onLoadTaskConcluded(loadable.loadTaskId);
|
||||
eventDispatcher.loadCompleted(
|
||||
mediaSourceEventDispatcher.loadCompleted(
|
||||
loadEventInfo,
|
||||
loadable.type,
|
||||
primaryTrackType,
|
||||
|
|
@ -438,7 +442,7 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
|
|||
loadDurationMs,
|
||||
loadable.bytesLoaded());
|
||||
loadErrorHandlingPolicy.onLoadTaskConcluded(loadable.loadTaskId);
|
||||
eventDispatcher.loadCanceled(
|
||||
mediaSourceEventDispatcher.loadCanceled(
|
||||
loadEventInfo,
|
||||
loadable.type,
|
||||
primaryTrackType,
|
||||
|
|
@ -519,7 +523,7 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
|
|||
}
|
||||
|
||||
boolean canceled = !loadErrorAction.isRetry();
|
||||
eventDispatcher.loadError(
|
||||
mediaSourceEventDispatcher.loadError(
|
||||
loadEventInfo,
|
||||
loadable.type,
|
||||
primaryTrackType,
|
||||
|
|
@ -593,7 +597,7 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
|
|||
long elapsedRealtimeMs =
|
||||
loader.startLoading(
|
||||
loadable, this, loadErrorHandlingPolicy.getMinimumLoadableRetryCount(loadable.type));
|
||||
eventDispatcher.loadStarted(
|
||||
mediaSourceEventDispatcher.loadStarted(
|
||||
new LoadEventInfo(loadable.loadTaskId, loadable.dataSpec, elapsedRealtimeMs),
|
||||
loadable.type,
|
||||
primaryTrackType,
|
||||
|
|
@ -648,7 +652,8 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
|
|||
pendingResetPositionUs = lastSeekPositionUs;
|
||||
}
|
||||
loadingFinished = false;
|
||||
eventDispatcher.upstreamDiscarded(primaryTrackType, firstRemovedChunk.startTimeUs, endTimeUs);
|
||||
mediaSourceEventDispatcher.upstreamDiscarded(
|
||||
primaryTrackType, firstRemovedChunk.startTimeUs, endTimeUs);
|
||||
}
|
||||
|
||||
// Internal methods
|
||||
|
|
@ -701,8 +706,11 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
|
|||
BaseMediaChunk currentChunk = mediaChunks.get(mediaChunkReadIndex);
|
||||
Format trackFormat = currentChunk.trackFormat;
|
||||
if (!trackFormat.equals(primaryDownstreamTrackFormat)) {
|
||||
eventDispatcher.downstreamFormatChanged(primaryTrackType, trackFormat,
|
||||
currentChunk.trackSelectionReason, currentChunk.trackSelectionData,
|
||||
mediaSourceEventDispatcher.downstreamFormatChanged(
|
||||
primaryTrackType,
|
||||
trackFormat,
|
||||
currentChunk.trackSelectionReason,
|
||||
currentChunk.trackSelectionData,
|
||||
currentChunk.startTimeUs);
|
||||
}
|
||||
primaryDownstreamTrackFormat = trackFormat;
|
||||
|
|
@ -812,7 +820,7 @@ public class ChunkSampleStream<T extends ChunkSource> implements SampleStream, S
|
|||
|
||||
private void maybeNotifyDownstreamFormat() {
|
||||
if (!notifiedDownstreamFormat) {
|
||||
eventDispatcher.downstreamFormatChanged(
|
||||
mediaSourceEventDispatcher.downstreamFormatChanged(
|
||||
embeddedTrackTypes[index],
|
||||
embeddedTrackFormats[index],
|
||||
C.SELECTION_REASON_UNKNOWN,
|
||||
|
|
|
|||
|
|
@ -1,203 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2020 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.util;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import androidx.annotation.CheckResult;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
|
||||
|
||||
/**
|
||||
* Event dispatcher which forwards events to a list of registered listeners.
|
||||
*
|
||||
* <p>Adds the correct {@code windowIndex} and {@code mediaPeriodId} values (and {@code
|
||||
* mediaTimeOffsetMs} if needed).
|
||||
*
|
||||
* <p>Allows listeners of any type to be registered, calls to {@link #dispatch} then provide the
|
||||
* type of listener to forward to, which is used to filter the registered listeners.
|
||||
*/
|
||||
// TODO: Make this final when MediaSourceEventListener.EventDispatcher is deleted.
|
||||
public class MediaSourceEventDispatcher {
|
||||
|
||||
/**
|
||||
* Functional interface to send an event with {@code windowIndex} and {@code mediaPeriodId}
|
||||
* attached.
|
||||
*/
|
||||
public interface EventWithPeriodId<T> {
|
||||
|
||||
/** Sends the event to a listener. */
|
||||
void sendTo(T listener, int windowIndex, @Nullable MediaPeriodId mediaPeriodId);
|
||||
}
|
||||
|
||||
/** The timeline window index reported with the events. */
|
||||
public final int windowIndex;
|
||||
/** The {@link MediaPeriodId} reported with the events. */
|
||||
@Nullable public final MediaPeriodId mediaPeriodId;
|
||||
|
||||
// TODO: Make these private when MediaSourceEventListener.EventDispatcher is deleted.
|
||||
protected final CopyOnWriteMultiset<ListenerInfo> listenerInfos;
|
||||
// TODO: Define exactly what this means, and check it's always set correctly.
|
||||
protected final long mediaTimeOffsetMs;
|
||||
|
||||
/** Creates an event dispatcher. */
|
||||
public MediaSourceEventDispatcher() {
|
||||
this(
|
||||
/* listenerInfos= */ new CopyOnWriteMultiset<>(),
|
||||
/* windowIndex= */ 0,
|
||||
/* mediaPeriodId= */ null,
|
||||
/* mediaTimeOffsetMs= */ 0);
|
||||
}
|
||||
|
||||
protected MediaSourceEventDispatcher(
|
||||
CopyOnWriteMultiset<ListenerInfo> listenerInfos,
|
||||
int windowIndex,
|
||||
@Nullable MediaPeriodId mediaPeriodId,
|
||||
long mediaTimeOffsetMs) {
|
||||
this.listenerInfos = listenerInfos;
|
||||
this.windowIndex = windowIndex;
|
||||
this.mediaPeriodId = mediaPeriodId;
|
||||
this.mediaTimeOffsetMs = mediaTimeOffsetMs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a view of the event dispatcher with pre-configured window index, media period id, and
|
||||
* media time offset.
|
||||
*
|
||||
* @param windowIndex The timeline window index to be reported with the events.
|
||||
* @param mediaPeriodId The {@link MediaPeriodId} to be reported with the events.
|
||||
* @param mediaTimeOffsetMs The offset to be added to all media times, in milliseconds.
|
||||
* @return A view of the event dispatcher with the pre-configured parameters.
|
||||
*/
|
||||
@CheckResult
|
||||
public MediaSourceEventDispatcher withParameters(
|
||||
int windowIndex, @Nullable MediaPeriodId mediaPeriodId, long mediaTimeOffsetMs) {
|
||||
return new MediaSourceEventDispatcher(
|
||||
listenerInfos, windowIndex, mediaPeriodId, mediaTimeOffsetMs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a listener to the event dispatcher.
|
||||
*
|
||||
* <p>Calls to {@link #dispatch(EventWithPeriodId, Class)} will propagate to {@code eventListener}
|
||||
* if the {@code listenerClass} types are equal.
|
||||
*
|
||||
* <p>The same listener instance can be added multiple times with different {@code listenerClass}
|
||||
* values (i.e. if the instance implements multiple listener interfaces).
|
||||
*
|
||||
* <p>Duplicate {@code {eventListener, listenerClass}} pairs are also permitted. In this case an
|
||||
* event dispatched to {@code listenerClass} will only be passed to the {@code eventListener}
|
||||
* once.
|
||||
*
|
||||
* <p><b>NOTE</b>: This doesn't interact well with hierarchies of listener interfaces. If a
|
||||
* listener is registered with a super-class type then it will only receive events dispatched
|
||||
* directly to that super-class type. Similarly, if a listener is registered with a sub-class type
|
||||
* then it will only receive events dispatched directly to that sub-class.
|
||||
*
|
||||
* @param handler A handler on the which listener events will be posted.
|
||||
* @param eventListener The listener to be added.
|
||||
* @param listenerClass The type used to register the listener. Can be a superclass of {@code
|
||||
* eventListener}.
|
||||
*/
|
||||
public <T> void addEventListener(Handler handler, T eventListener, Class<T> listenerClass) {
|
||||
Assertions.checkNotNull(handler);
|
||||
Assertions.checkNotNull(eventListener);
|
||||
listenerInfos.add(new ListenerInfo(handler, eventListener, listenerClass));
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a listener from the event dispatcher.
|
||||
*
|
||||
* <p>If there are duplicate registrations of {@code {eventListener, listenerClass}} this will
|
||||
* only remove one (so events dispatched to {@code listenerClass} will still be passed to {@code
|
||||
* eventListener}).
|
||||
*
|
||||
* @param eventListener The listener to be removed.
|
||||
* @param listenerClass The listener type passed to {@link #addEventListener(Handler, Object,
|
||||
* Class)}.
|
||||
*/
|
||||
public <T> void removeEventListener(T eventListener, Class<T> listenerClass) {
|
||||
for (ListenerInfo listenerInfo : listenerInfos) {
|
||||
if (listenerInfo.listener == eventListener
|
||||
&& listenerInfo.listenerClass.equals(listenerClass)) {
|
||||
listenerInfos.remove(listenerInfo);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Dispatches {@code event} to all registered listeners of type {@code listenerClass}. */
|
||||
@SuppressWarnings("unchecked") // The cast is gated with listenerClass.isInstance()
|
||||
public <T> void dispatch(EventWithPeriodId<T> event, Class<T> listenerClass) {
|
||||
for (ListenerInfo listenerInfo : listenerInfos.elementSet()) {
|
||||
if (listenerInfo.listenerClass.equals(listenerClass)) {
|
||||
postOrRun(
|
||||
listenerInfo.handler,
|
||||
() -> event.sendTo((T) listenerInfo.listener, windowIndex, mediaPeriodId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void postOrRun(Handler handler, Runnable runnable) {
|
||||
if (handler.getLooper() == Looper.myLooper()) {
|
||||
runnable.run();
|
||||
} else {
|
||||
handler.post(runnable);
|
||||
}
|
||||
}
|
||||
|
||||
public static long adjustMediaTime(long mediaTimeUs, long mediaTimeOffsetMs) {
|
||||
long mediaTimeMs = C.usToMs(mediaTimeUs);
|
||||
return mediaTimeMs == C.TIME_UNSET ? C.TIME_UNSET : mediaTimeOffsetMs + mediaTimeMs;
|
||||
}
|
||||
|
||||
/** Container class for a {@link Handler}, {@code listener} and {@code listenerClass}. */
|
||||
protected static final class ListenerInfo {
|
||||
|
||||
public final Handler handler;
|
||||
public final Object listener;
|
||||
public final Class<?> listenerClass;
|
||||
|
||||
public ListenerInfo(Handler handler, Object listener, Class<?> listenerClass) {
|
||||
this.handler = handler;
|
||||
this.listener = listener;
|
||||
this.listenerClass = listenerClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof ListenerInfo)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ListenerInfo that = (ListenerInfo) o;
|
||||
|
||||
// We deliberately only consider listener and listenerClass (and not handler) in equals() and
|
||||
// hashcode() because the handler used to process the callbacks is an implementation detail.
|
||||
return listener.equals(that.listener) && listenerClass.equals(that.listenerClass);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = 31 * listener.hashCode();
|
||||
return result + 31 * listenerClass.hashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -44,6 +44,7 @@ import com.google.android.exoplayer2.Player.EventListener;
|
|||
import com.google.android.exoplayer2.Timeline.Window;
|
||||
import com.google.android.exoplayer2.analytics.AnalyticsListener;
|
||||
import com.google.android.exoplayer2.audio.AudioAttributes;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionEventListener;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.source.ClippingMediaSource;
|
||||
import com.google.android.exoplayer2.source.CompositeMediaSource;
|
||||
|
|
@ -53,7 +54,7 @@ import com.google.android.exoplayer2.source.MaskingMediaSource;
|
|||
import com.google.android.exoplayer2.source.MediaPeriod;
|
||||
import com.google.android.exoplayer2.source.MediaSource;
|
||||
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
|
||||
import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher;
|
||||
import com.google.android.exoplayer2.source.MediaSourceEventListener;
|
||||
import com.google.android.exoplayer2.source.SampleStream;
|
||||
import com.google.android.exoplayer2.source.SilenceMediaSource;
|
||||
import com.google.android.exoplayer2.source.TrackGroup;
|
||||
|
|
@ -616,15 +617,17 @@ public final class ExoPlayerTest {
|
|||
MediaPeriodId id,
|
||||
TrackGroupArray trackGroupArray,
|
||||
Allocator allocator,
|
||||
MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher,
|
||||
DrmSessionManager drmSessionManager,
|
||||
EventDispatcher eventDispatcher,
|
||||
DrmSessionEventListener.EventDispatcher drmEventDispatcher,
|
||||
@Nullable TransferListener transferListener) {
|
||||
FakeMediaPeriod mediaPeriod =
|
||||
new FakeMediaPeriod(
|
||||
trackGroupArray,
|
||||
TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US,
|
||||
eventDispatcher,
|
||||
mediaSourceEventDispatcher,
|
||||
drmSessionManager,
|
||||
drmEventDispatcher,
|
||||
/* deferOnPrepared= */ false);
|
||||
mediaPeriod.setSeekToUsOffset(10);
|
||||
return mediaPeriod;
|
||||
|
|
@ -658,14 +661,15 @@ public final class ExoPlayerTest {
|
|||
MediaPeriodId id,
|
||||
TrackGroupArray trackGroupArray,
|
||||
Allocator allocator,
|
||||
MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher,
|
||||
DrmSessionManager drmSessionManager,
|
||||
EventDispatcher eventDispatcher,
|
||||
DrmSessionEventListener.EventDispatcher drmEventDispatcher,
|
||||
@Nullable TransferListener transferListener) {
|
||||
FakeMediaPeriod mediaPeriod =
|
||||
new FakeMediaPeriod(
|
||||
trackGroupArray,
|
||||
TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US,
|
||||
eventDispatcher);
|
||||
mediaSourceEventDispatcher);
|
||||
mediaPeriod.setDiscontinuityPositionUs(10);
|
||||
return mediaPeriod;
|
||||
}
|
||||
|
|
@ -689,14 +693,15 @@ public final class ExoPlayerTest {
|
|||
MediaPeriodId id,
|
||||
TrackGroupArray trackGroupArray,
|
||||
Allocator allocator,
|
||||
MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher,
|
||||
DrmSessionManager drmSessionManager,
|
||||
EventDispatcher eventDispatcher,
|
||||
DrmSessionEventListener.EventDispatcher drmEventDispatcher,
|
||||
@Nullable TransferListener transferListener) {
|
||||
FakeMediaPeriod mediaPeriod =
|
||||
new FakeMediaPeriod(
|
||||
trackGroupArray,
|
||||
TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US,
|
||||
eventDispatcher);
|
||||
mediaSourceEventDispatcher);
|
||||
// Set a discontinuity at the position this period is supposed to start at anyway.
|
||||
mediaPeriod.setDiscontinuityPositionUs(
|
||||
timeline.getWindow(/* windowIndex= */ 0, new Window()).positionInFirstPeriodUs);
|
||||
|
|
@ -938,16 +943,18 @@ public final class ExoPlayerTest {
|
|||
MediaPeriodId id,
|
||||
TrackGroupArray trackGroupArray,
|
||||
Allocator allocator,
|
||||
MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher,
|
||||
DrmSessionManager drmSessionManager,
|
||||
EventDispatcher eventDispatcher,
|
||||
DrmSessionEventListener.EventDispatcher drmEventDispatcher,
|
||||
@Nullable TransferListener transferListener) {
|
||||
// Defer completing preparation of the period until playback parameters have been set.
|
||||
fakeMediaPeriodHolder[0] =
|
||||
new FakeMediaPeriod(
|
||||
trackGroupArray,
|
||||
TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US,
|
||||
eventDispatcher,
|
||||
mediaSourceEventDispatcher,
|
||||
drmSessionManager,
|
||||
drmEventDispatcher,
|
||||
/* deferOnPrepared= */ true);
|
||||
createPeriodCalledCountDownLatch.countDown();
|
||||
return fakeMediaPeriodHolder[0];
|
||||
|
|
@ -990,16 +997,18 @@ public final class ExoPlayerTest {
|
|||
MediaPeriodId id,
|
||||
TrackGroupArray trackGroupArray,
|
||||
Allocator allocator,
|
||||
MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher,
|
||||
DrmSessionManager drmSessionManager,
|
||||
EventDispatcher eventDispatcher,
|
||||
DrmSessionEventListener.EventDispatcher drmEventDispatcher,
|
||||
@Nullable TransferListener transferListener) {
|
||||
// Defer completing preparation of the period until seek has been sent.
|
||||
fakeMediaPeriodHolder[0] =
|
||||
new FakeMediaPeriod(
|
||||
trackGroupArray,
|
||||
TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US,
|
||||
eventDispatcher,
|
||||
mediaSourceEventDispatcher,
|
||||
drmSessionManager,
|
||||
drmEventDispatcher,
|
||||
/* deferOnPrepared= */ true);
|
||||
createPeriodCalledCountDownLatch.countDown();
|
||||
return fakeMediaPeriodHolder[0];
|
||||
|
|
@ -3723,13 +3732,14 @@ public final class ExoPlayerTest {
|
|||
MediaPeriodId id,
|
||||
TrackGroupArray trackGroupArray,
|
||||
Allocator allocator,
|
||||
MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher,
|
||||
DrmSessionManager drmSessionManager,
|
||||
EventDispatcher eventDispatcher,
|
||||
DrmSessionEventListener.EventDispatcher drmEventDispatcher,
|
||||
@Nullable TransferListener transferListener) {
|
||||
return new FakeMediaPeriod(
|
||||
trackGroupArray,
|
||||
TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US,
|
||||
eventDispatcher) {
|
||||
mediaSourceEventDispatcher) {
|
||||
@Override
|
||||
public long getBufferedPositionUs() {
|
||||
// Pretend not to have buffered data yet.
|
||||
|
|
@ -6365,13 +6375,14 @@ public final class ExoPlayerTest {
|
|||
MediaPeriodId id,
|
||||
TrackGroupArray trackGroupArray,
|
||||
Allocator allocator,
|
||||
MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher,
|
||||
DrmSessionManager drmSessionManager,
|
||||
EventDispatcher eventDispatcher,
|
||||
DrmSessionEventListener.EventDispatcher drmEventDispatcher,
|
||||
@Nullable TransferListener transferListener) {
|
||||
return new FakeMediaPeriod(
|
||||
trackGroupArray,
|
||||
TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US,
|
||||
eventDispatcher) {
|
||||
mediaSourceEventDispatcher) {
|
||||
|
||||
private final List<Allocation> allocations = new ArrayList<>();
|
||||
|
||||
|
|
@ -6444,14 +6455,16 @@ public final class ExoPlayerTest {
|
|||
MediaPeriodId id,
|
||||
TrackGroupArray trackGroupArray,
|
||||
Allocator allocator,
|
||||
MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher,
|
||||
DrmSessionManager drmSessionManager,
|
||||
EventDispatcher eventDispatcher,
|
||||
DrmSessionEventListener.EventDispatcher drmEventDispatcher,
|
||||
@Nullable TransferListener transferListener) {
|
||||
return new FakeMediaPeriod(
|
||||
trackGroupArray,
|
||||
TimelineWindowDefinition.DEFAULT_WINDOW_OFFSET_IN_FIRST_PERIOD_US,
|
||||
eventDispatcher,
|
||||
mediaSourceEventDispatcher,
|
||||
drmSessionManager,
|
||||
drmEventDispatcher,
|
||||
/* deferOnPrepared= */ false) {
|
||||
private Loader loader = new Loader("oomLoader");
|
||||
|
||||
|
|
@ -6466,13 +6479,15 @@ public final class ExoPlayerTest {
|
|||
protected SampleStream createSampleStream(
|
||||
long positionUs,
|
||||
TrackSelection selection,
|
||||
MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher,
|
||||
DrmSessionManager drmSessionManager,
|
||||
EventDispatcher eventDispatcher) {
|
||||
DrmSessionEventListener.EventDispatcher drmEventDispatcher) {
|
||||
// Create 3 samples without end of stream signal to test that all 3 samples are
|
||||
// still played before the exception is thrown.
|
||||
return new FakeSampleStream(
|
||||
mediaSourceEventDispatcher,
|
||||
drmSessionManager,
|
||||
eventDispatcher,
|
||||
drmEventDispatcher,
|
||||
selection.getSelectedFormat(),
|
||||
ImmutableList.of(
|
||||
oneByteSample(positionUs),
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ import com.google.android.exoplayer2.decoder.DecoderException;
|
|||
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
|
||||
import com.google.android.exoplayer2.decoder.SimpleDecoder;
|
||||
import com.google.android.exoplayer2.decoder.SimpleOutputBuffer;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionEventListener;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.drm.ExoMediaCrypto;
|
||||
import com.google.android.exoplayer2.testutil.FakeSampleStream;
|
||||
|
|
@ -107,8 +108,9 @@ public class DecoderAudioRendererTest {
|
|||
RendererConfiguration.DEFAULT,
|
||||
new Format[] {FORMAT},
|
||||
new FakeSampleStream(
|
||||
/* mediaSourceEventDispatcher= */ null,
|
||||
DrmSessionManager.DUMMY,
|
||||
/* eventDispatcher= */ null,
|
||||
new DrmSessionEventListener.EventDispatcher(),
|
||||
FORMAT,
|
||||
ImmutableList.of(END_OF_STREAM_ITEM)),
|
||||
/* positionUs= */ 0,
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ import com.google.android.exoplayer2.C;
|
|||
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.RendererConfiguration;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionEventListener;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.mediacodec.MediaCodecInfo;
|
||||
import com.google.android.exoplayer2.mediacodec.MediaCodecSelector;
|
||||
|
|
@ -111,8 +112,9 @@ public class MediaCodecAudioRendererTest {
|
|||
|
||||
FakeSampleStream fakeSampleStream =
|
||||
new FakeSampleStream(
|
||||
/* mediaSourceEventDispatcher= */ null,
|
||||
DrmSessionManager.DUMMY,
|
||||
/* eventDispatcher= */ null,
|
||||
new DrmSessionEventListener.EventDispatcher(),
|
||||
/* initialFormat= */ AUDIO_AAC,
|
||||
ImmutableList.of(
|
||||
oneByteSample(/* timeUs= */ 0, C.BUFFER_FLAG_KEY_FRAME),
|
||||
|
|
@ -158,8 +160,9 @@ public class MediaCodecAudioRendererTest {
|
|||
|
||||
FakeSampleStream fakeSampleStream =
|
||||
new FakeSampleStream(
|
||||
/* mediaSourceEventDispatcher= */ null,
|
||||
DrmSessionManager.DUMMY,
|
||||
/* eventDispatcher= */ null,
|
||||
new DrmSessionEventListener.EventDispatcher(),
|
||||
/* initialFormat= */ AUDIO_AAC,
|
||||
ImmutableList.of(
|
||||
oneByteSample(/* timeUs= */ 0, C.BUFFER_FLAG_KEY_FRAME),
|
||||
|
|
@ -225,8 +228,9 @@ public class MediaCodecAudioRendererTest {
|
|||
|
||||
FakeSampleStream fakeSampleStream =
|
||||
new FakeSampleStream(
|
||||
/* mediaSourceEventDispatcher= */ null,
|
||||
DrmSessionManager.DUMMY,
|
||||
/* eventDispatcher= */ null,
|
||||
new DrmSessionEventListener.EventDispatcher(),
|
||||
/* initialFormat= */ AUDIO_AAC,
|
||||
ImmutableList.of(
|
||||
oneByteSample(/* timeUs= */ 0, C.BUFFER_FLAG_KEY_FRAME), END_OF_STREAM_ITEM));
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ import android.util.Pair;
|
|||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.drm.DrmInitData.SchemeData;
|
||||
import com.google.android.exoplayer2.util.MediaSourceEventDispatcher;
|
||||
import java.util.HashMap;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
|
@ -57,7 +56,7 @@ public class OfflineLicenseHelperTest {
|
|||
new ExoMediaDrm.AppManagedProvider(mediaDrm),
|
||||
mediaDrmCallback,
|
||||
/* optionalKeyRequestParameters= */ null,
|
||||
new MediaSourceEventDispatcher());
|
||||
new DrmSessionEventListener.EventDispatcher());
|
||||
}
|
||||
|
||||
@After
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import static java.nio.charset.StandardCharsets.UTF_8;
|
|||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionEventListener;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.metadata.emsg.EventMessage;
|
||||
import com.google.android.exoplayer2.metadata.emsg.EventMessageEncoder;
|
||||
|
|
@ -146,8 +147,9 @@ public class MetadataRendererTest {
|
|||
renderer.replaceStream(
|
||||
new Format[] {EMSG_FORMAT},
|
||||
new FakeSampleStream(
|
||||
/* mediaSourceEventDispatcher= */ null,
|
||||
DrmSessionManager.DUMMY,
|
||||
/* eventDispatcher= */ null,
|
||||
new DrmSessionEventListener.EventDispatcher(),
|
||||
EMSG_FORMAT,
|
||||
ImmutableList.of(
|
||||
FakeSampleStreamItem.sample(/* timeUs= */ 0, /* flags= */ 0, input),
|
||||
|
|
|
|||
|
|
@ -27,11 +27,11 @@ import com.google.android.exoplayer2.Player;
|
|||
import com.google.android.exoplayer2.Timeline;
|
||||
import com.google.android.exoplayer2.Timeline.Period;
|
||||
import com.google.android.exoplayer2.Timeline.Window;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionEventListener;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.source.ClippingMediaSource.IllegalClippingException;
|
||||
import com.google.android.exoplayer2.source.MaskingMediaSource.DummyTimeline;
|
||||
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
|
||||
import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher;
|
||||
import com.google.android.exoplayer2.testutil.FakeMediaPeriod;
|
||||
import com.google.android.exoplayer2.testutil.FakeMediaSource;
|
||||
import com.google.android.exoplayer2.testutil.FakeTimeline;
|
||||
|
|
@ -569,10 +569,11 @@ public final class ClippingMediaSourceTest {
|
|||
MediaPeriodId id,
|
||||
TrackGroupArray trackGroupArray,
|
||||
Allocator allocator,
|
||||
MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher,
|
||||
DrmSessionManager drmSessionManager,
|
||||
EventDispatcher eventDispatcher,
|
||||
DrmSessionEventListener.EventDispatcher drmEventDispatcher,
|
||||
@Nullable TransferListener transferListener) {
|
||||
eventDispatcher.downstreamFormatChanged(
|
||||
mediaSourceEventDispatcher.downstreamFormatChanged(
|
||||
new MediaLoadData(
|
||||
C.DATA_TYPE_MEDIA,
|
||||
C.TRACK_TYPE_UNKNOWN,
|
||||
|
|
@ -585,8 +586,9 @@ public final class ClippingMediaSourceTest {
|
|||
id,
|
||||
trackGroupArray,
|
||||
allocator,
|
||||
mediaSourceEventDispatcher,
|
||||
drmSessionManager,
|
||||
eventDispatcher,
|
||||
drmEventDispatcher,
|
||||
transferListener);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import com.google.android.exoplayer2.C;
|
|||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.FormatHolder;
|
||||
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionEventListener;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
|
||||
import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher;
|
||||
|
|
@ -200,13 +201,14 @@ public final class MergingMediaPeriodTest {
|
|||
|
||||
public FakeMediaPeriodWithSelectTracksPosition(
|
||||
TrackGroupArray trackGroupArray,
|
||||
EventDispatcher eventDispatcher,
|
||||
EventDispatcher mediaSourceEventDispatcher,
|
||||
TrackDataFactory trackDataFactory) {
|
||||
super(
|
||||
trackGroupArray,
|
||||
trackDataFactory,
|
||||
eventDispatcher,
|
||||
mediaSourceEventDispatcher,
|
||||
DrmSessionManager.DUMMY,
|
||||
new DrmSessionEventListener.EventDispatcher(),
|
||||
/* deferOnPrepared= */ false);
|
||||
selectTracksPositionUs = C.TIME_UNSET;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import android.net.Uri;
|
|||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionEventListener;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.extractor.Extractor;
|
||||
import com.google.android.exoplayer2.extractor.mp4.Mp4Extractor;
|
||||
|
|
@ -44,18 +45,18 @@ public final class ProgressiveMediaPeriodTest {
|
|||
AtomicBoolean sourceInfoRefreshCalled = new AtomicBoolean(false);
|
||||
ProgressiveMediaPeriod.Listener sourceInfoRefreshListener =
|
||||
(durationUs, isSeekable, isLive) -> sourceInfoRefreshCalled.set(true);
|
||||
MediaPeriodId mediaPeriodId = new MediaPeriodId(/* periodUid= */ new Object());
|
||||
ProgressiveMediaPeriod mediaPeriod =
|
||||
new ProgressiveMediaPeriod(
|
||||
Uri.parse("asset://android_asset/mp4/sample.mp4"),
|
||||
new AssetDataSource(ApplicationProvider.getApplicationContext()),
|
||||
() -> new Extractor[] {new Mp4Extractor()},
|
||||
DrmSessionManager.DUMMY,
|
||||
new DrmSessionEventListener.EventDispatcher()
|
||||
.withParameters(/* windowIndex= */ 0, mediaPeriodId),
|
||||
new DefaultLoadErrorHandlingPolicy(),
|
||||
new MediaSourceEventListener.EventDispatcher()
|
||||
.withParameters(
|
||||
/* windowIndex= */ 0,
|
||||
new MediaPeriodId(/* periodUid= */ new Object()),
|
||||
/* mediaTimeOffsetMs= */ 0),
|
||||
.withParameters(/* windowIndex= */ 0, mediaPeriodId, /* mediaTimeOffsetMs= */ 0),
|
||||
sourceInfoRefreshListener,
|
||||
new DefaultAllocator(/* trimOnReset= */ true, C.DEFAULT_BUFFER_SEGMENT_SIZE),
|
||||
/* customCacheKey= */ null,
|
||||
|
|
|
|||
|
|
@ -35,13 +35,13 @@ import com.google.android.exoplayer2.FormatHolder;
|
|||
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
|
||||
import com.google.android.exoplayer2.drm.DrmInitData;
|
||||
import com.google.android.exoplayer2.drm.DrmSession;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionEventListener;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.extractor.TrackOutput;
|
||||
import com.google.android.exoplayer2.testutil.TestUtil;
|
||||
import com.google.android.exoplayer2.upstream.Allocator;
|
||||
import com.google.android.exoplayer2.upstream.DefaultAllocator;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.MediaSourceEventDispatcher;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||
import com.google.common.primitives.Bytes;
|
||||
|
|
@ -129,7 +129,7 @@ public final class SampleQueueTest {
|
|||
private Allocator allocator;
|
||||
private DrmSessionManager mockDrmSessionManager;
|
||||
private DrmSession mockDrmSession;
|
||||
private MediaSourceEventDispatcher eventDispatcher;
|
||||
private DrmSessionEventListener.EventDispatcher eventDispatcher;
|
||||
private SampleQueue sampleQueue;
|
||||
private FormatHolder formatHolder;
|
||||
private DecoderInputBuffer inputBuffer;
|
||||
|
|
@ -142,7 +142,7 @@ public final class SampleQueueTest {
|
|||
when(mockDrmSessionManager.acquireSession(
|
||||
ArgumentMatchers.any(), ArgumentMatchers.any(), ArgumentMatchers.any()))
|
||||
.thenReturn(mockDrmSession);
|
||||
eventDispatcher = new MediaSourceEventDispatcher();
|
||||
eventDispatcher = new DrmSessionEventListener.EventDispatcher();
|
||||
sampleQueue =
|
||||
new SampleQueue(
|
||||
allocator,
|
||||
|
|
|
|||
|
|
@ -1,236 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2020 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.util;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyInt;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionEventListener;
|
||||
import com.google.android.exoplayer2.source.MediaSource;
|
||||
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
|
||||
import com.google.android.exoplayer2.source.MediaSourceEventListener;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.MockitoJUnit;
|
||||
import org.mockito.junit.MockitoRule;
|
||||
|
||||
/** Tests for {@link MediaSourceEventDispatcher}. */
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class MediaSourceEventDispatcherTest {
|
||||
|
||||
private static final MediaSource.MediaPeriodId MEDIA_PERIOD_ID =
|
||||
new MediaSource.MediaPeriodId("test uid");
|
||||
private static final int WINDOW_INDEX = 200;
|
||||
private static final int MEDIA_TIME_OFFSET_MS = 1_000;
|
||||
|
||||
@Rule public final MockitoRule mockito = MockitoJUnit.rule();
|
||||
|
||||
@Mock private MediaSourceEventListener mediaSourceEventListener;
|
||||
@Mock private MediaAndDrmEventListener mediaAndDrmEventListener;
|
||||
|
||||
private MediaSourceEventDispatcher eventDispatcher;
|
||||
|
||||
@Before
|
||||
public void setupEventDispatcher() {
|
||||
eventDispatcher = new MediaSourceEventDispatcher();
|
||||
eventDispatcher =
|
||||
eventDispatcher.withParameters(WINDOW_INDEX, MEDIA_PERIOD_ID, MEDIA_TIME_OFFSET_MS);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void listenerReceivesEventPopulatedWithMediaPeriodInfo() {
|
||||
eventDispatcher.addEventListener(
|
||||
Util.createHandlerForCurrentOrMainLooper(),
|
||||
mediaSourceEventListener,
|
||||
MediaSourceEventListener.class);
|
||||
|
||||
eventDispatcher.dispatch(
|
||||
MediaSourceEventListener::onMediaPeriodCreated, MediaSourceEventListener.class);
|
||||
|
||||
verify(mediaSourceEventListener).onMediaPeriodCreated(WINDOW_INDEX, MEDIA_PERIOD_ID);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sameListenerObjectRegisteredTwiceOnlyReceivesEventsOnce() {
|
||||
eventDispatcher.addEventListener(
|
||||
Util.createHandlerForCurrentOrMainLooper(),
|
||||
mediaSourceEventListener,
|
||||
MediaSourceEventListener.class);
|
||||
eventDispatcher.addEventListener(
|
||||
Util.createHandlerForCurrentOrMainLooper(),
|
||||
mediaSourceEventListener,
|
||||
MediaSourceEventListener.class);
|
||||
|
||||
eventDispatcher.dispatch(
|
||||
MediaSourceEventListener::onMediaPeriodCreated, MediaSourceEventListener.class);
|
||||
|
||||
verify(mediaSourceEventListener).onMediaPeriodCreated(WINDOW_INDEX, MEDIA_PERIOD_ID);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sameListenerInstanceCanBeRegisteredWithTwoTypes() {
|
||||
eventDispatcher.addEventListener(
|
||||
new Handler(Looper.getMainLooper()),
|
||||
mediaAndDrmEventListener,
|
||||
MediaSourceEventListener.class);
|
||||
eventDispatcher.addEventListener(
|
||||
new Handler(Looper.getMainLooper()),
|
||||
mediaAndDrmEventListener,
|
||||
DrmSessionEventListener.class);
|
||||
|
||||
eventDispatcher.dispatch(
|
||||
MediaSourceEventListener::onMediaPeriodCreated, MediaSourceEventListener.class);
|
||||
eventDispatcher.dispatch(
|
||||
DrmSessionEventListener::onDrmKeysLoaded, DrmSessionEventListener.class);
|
||||
|
||||
verify(mediaAndDrmEventListener).onMediaPeriodCreated(WINDOW_INDEX, MEDIA_PERIOD_ID);
|
||||
verify(mediaAndDrmEventListener).onDrmKeysLoaded(WINDOW_INDEX, MEDIA_PERIOD_ID);
|
||||
}
|
||||
|
||||
// If a listener is added that implements multiple types, it should only receive events for the
|
||||
// type specified at registration time.
|
||||
@Test
|
||||
public void listenerOnlyReceivesEventsForRegisteredType() {
|
||||
eventDispatcher.addEventListener(
|
||||
new Handler(Looper.getMainLooper()),
|
||||
mediaAndDrmEventListener,
|
||||
MediaSourceEventListener.class);
|
||||
|
||||
eventDispatcher.dispatch(
|
||||
MediaSourceEventListener::onMediaPeriodCreated, MediaSourceEventListener.class);
|
||||
eventDispatcher.dispatch(
|
||||
DrmSessionEventListener::onDrmKeysLoaded, DrmSessionEventListener.class);
|
||||
|
||||
verify(mediaAndDrmEventListener).onMediaPeriodCreated(WINDOW_INDEX, MEDIA_PERIOD_ID);
|
||||
verify(mediaAndDrmEventListener, never()).onDrmKeysLoaded(WINDOW_INDEX, MEDIA_PERIOD_ID);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void listenerDoesntReceiveEventsDispatchedToSubclass() {
|
||||
SubclassListener subclassListener = mock(SubclassListener.class);
|
||||
eventDispatcher.addEventListener(
|
||||
new Handler(Looper.getMainLooper()), subclassListener, MediaSourceEventListener.class);
|
||||
|
||||
eventDispatcher.dispatch(SubclassListener::subclassMethod, SubclassListener.class);
|
||||
|
||||
// subclassListener can handle the call to subclassMethod, but it isn't called because
|
||||
// it was registered 'as-a' MediaSourceEventListener, not SubclassListener.
|
||||
verify(subclassListener, never()).subclassMethod(anyInt(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void listenerDoesntReceiveEventsDispatchedToSuperclass() {
|
||||
SubclassListener subclassListener = mock(SubclassListener.class);
|
||||
eventDispatcher.addEventListener(
|
||||
new Handler(Looper.getMainLooper()), subclassListener, SubclassListener.class);
|
||||
|
||||
eventDispatcher.dispatch(
|
||||
MediaSourceEventListener::onMediaPeriodCreated, MediaSourceEventListener.class);
|
||||
|
||||
// subclassListener 'is-a' a MediaSourceEventListener, but it isn't called because the event
|
||||
// is dispatched specifically to listeners registered as MediaSourceEventListener.
|
||||
verify(subclassListener, never()).onMediaPeriodCreated(anyInt(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void listenersAreCopiedToNewDispatcher() {
|
||||
eventDispatcher.addEventListener(
|
||||
Util.createHandlerForCurrentOrMainLooper(),
|
||||
mediaSourceEventListener,
|
||||
MediaSourceEventListener.class);
|
||||
|
||||
MediaSource.MediaPeriodId newPeriodId = new MediaSource.MediaPeriodId("different uid");
|
||||
MediaSourceEventDispatcher newEventDispatcher =
|
||||
this.eventDispatcher.withParameters(
|
||||
/* windowIndex= */ 250, newPeriodId, /* mediaTimeOffsetMs= */ 500);
|
||||
|
||||
newEventDispatcher.dispatch(
|
||||
MediaSourceEventListener::onMediaPeriodCreated, MediaSourceEventListener.class);
|
||||
|
||||
verify(mediaSourceEventListener).onMediaPeriodCreated(250, newPeriodId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removingListenerStopsEventDispatch() {
|
||||
eventDispatcher.addEventListener(
|
||||
Util.createHandlerForCurrentOrMainLooper(),
|
||||
mediaSourceEventListener,
|
||||
MediaSourceEventListener.class);
|
||||
eventDispatcher.removeEventListener(mediaSourceEventListener, MediaSourceEventListener.class);
|
||||
|
||||
eventDispatcher.dispatch(
|
||||
MediaSourceEventListener::onMediaPeriodCreated, MediaSourceEventListener.class);
|
||||
|
||||
verify(mediaSourceEventListener, never()).onMediaPeriodCreated(anyInt(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void removingListenerWithDifferentTypeToRegistrationDoesntRemove() {
|
||||
eventDispatcher.addEventListener(
|
||||
Util.createHandlerForCurrentOrMainLooper(),
|
||||
mediaAndDrmEventListener,
|
||||
MediaSourceEventListener.class);
|
||||
eventDispatcher.removeEventListener(mediaAndDrmEventListener, DrmSessionEventListener.class);
|
||||
|
||||
eventDispatcher.dispatch(
|
||||
MediaSourceEventListener::onMediaPeriodCreated, MediaSourceEventListener.class);
|
||||
|
||||
verify(mediaAndDrmEventListener).onMediaPeriodCreated(WINDOW_INDEX, MEDIA_PERIOD_ID);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void listenersAreCountedBasedOnListenerAndType() {
|
||||
// Add the listener twice and remove it once.
|
||||
eventDispatcher.addEventListener(
|
||||
Util.createHandlerForCurrentOrMainLooper(),
|
||||
mediaSourceEventListener,
|
||||
MediaSourceEventListener.class);
|
||||
eventDispatcher.addEventListener(
|
||||
Util.createHandlerForCurrentOrMainLooper(),
|
||||
mediaSourceEventListener,
|
||||
MediaSourceEventListener.class);
|
||||
eventDispatcher.removeEventListener(mediaSourceEventListener, MediaSourceEventListener.class);
|
||||
|
||||
eventDispatcher.dispatch(
|
||||
MediaSourceEventListener::onMediaPeriodCreated, MediaSourceEventListener.class);
|
||||
|
||||
verify(mediaSourceEventListener).onMediaPeriodCreated(WINDOW_INDEX, MEDIA_PERIOD_ID);
|
||||
|
||||
// Remove it a second time and confirm the events stop being propagated.
|
||||
eventDispatcher.removeEventListener(mediaSourceEventListener, MediaSourceEventListener.class);
|
||||
|
||||
verifyNoMoreInteractions(mediaSourceEventListener);
|
||||
}
|
||||
|
||||
private interface MediaAndDrmEventListener
|
||||
extends MediaSourceEventListener, DrmSessionEventListener {}
|
||||
|
||||
private interface SubclassListener extends MediaSourceEventListener {
|
||||
void subclassMethod(int windowIndex, @Nullable MediaPeriodId mediaPeriodId);
|
||||
}
|
||||
}
|
||||
|
|
@ -35,6 +35,7 @@ import com.google.android.exoplayer2.RendererConfiguration;
|
|||
import com.google.android.exoplayer2.decoder.DecoderException;
|
||||
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
|
||||
import com.google.android.exoplayer2.decoder.SimpleDecoder;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionEventListener;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.drm.ExoMediaCrypto;
|
||||
import com.google.android.exoplayer2.testutil.FakeSampleStream;
|
||||
|
|
@ -185,8 +186,9 @@ public final class DecoderVideoRendererTest {
|
|||
public void enable_withMayRenderStartOfStream_rendersFirstFrameBeforeStart() throws Exception {
|
||||
FakeSampleStream fakeSampleStream =
|
||||
new FakeSampleStream(
|
||||
/* mediaSourceEventDispatcher= */ null,
|
||||
DrmSessionManager.DUMMY,
|
||||
/* eventDispatcher= */ null,
|
||||
new DrmSessionEventListener.EventDispatcher(),
|
||||
/* initialFormat= */ H264_FORMAT,
|
||||
ImmutableList.of(oneByteSample(/* timeUs= */ 0)));
|
||||
|
||||
|
|
@ -212,8 +214,9 @@ public final class DecoderVideoRendererTest {
|
|||
throws Exception {
|
||||
FakeSampleStream fakeSampleStream =
|
||||
new FakeSampleStream(
|
||||
/* mediaSourceEventDispatcher= */ null,
|
||||
DrmSessionManager.DUMMY,
|
||||
/* eventDispatcher= */ null,
|
||||
new DrmSessionEventListener.EventDispatcher(),
|
||||
/* initialFormat= */ H264_FORMAT,
|
||||
ImmutableList.of(oneByteSample(/* timeUs= */ 0)));
|
||||
|
||||
|
|
@ -238,8 +241,9 @@ public final class DecoderVideoRendererTest {
|
|||
public void enable_withoutMayRenderStartOfStream_rendersFirstFrameAfterStart() throws Exception {
|
||||
FakeSampleStream fakeSampleStream =
|
||||
new FakeSampleStream(
|
||||
/* mediaSourceEventDispatcher= */ null,
|
||||
DrmSessionManager.DUMMY,
|
||||
/* eventDispatcher= */ null,
|
||||
new DrmSessionEventListener.EventDispatcher(),
|
||||
/* initialFormat= */ H264_FORMAT,
|
||||
ImmutableList.of(oneByteSample(/* timeUs= */ 0)));
|
||||
|
||||
|
|
@ -267,15 +271,17 @@ public final class DecoderVideoRendererTest {
|
|||
public void replaceStream_whenStarted_rendersFirstFrameOfNewStream() throws Exception {
|
||||
FakeSampleStream fakeSampleStream1 =
|
||||
new FakeSampleStream(
|
||||
/* mediaSourceEventDispatcher= */ null,
|
||||
DrmSessionManager.DUMMY,
|
||||
/* eventDispatcher= */ null,
|
||||
new DrmSessionEventListener.EventDispatcher(),
|
||||
/* initialFormat= */ H264_FORMAT,
|
||||
ImmutableList.of(
|
||||
oneByteSample(/* timeUs= */ 0), FakeSampleStreamItem.END_OF_STREAM_ITEM));
|
||||
FakeSampleStream fakeSampleStream2 =
|
||||
new FakeSampleStream(
|
||||
/* mediaSourceEventDispatcher= */ null,
|
||||
DrmSessionManager.DUMMY,
|
||||
/* eventDispatcher= */ null,
|
||||
new DrmSessionEventListener.EventDispatcher(),
|
||||
/* initialFormat= */ H264_FORMAT,
|
||||
ImmutableList.of(
|
||||
oneByteSample(/* timeUs= */ 0), FakeSampleStreamItem.END_OF_STREAM_ITEM));
|
||||
|
|
@ -309,15 +315,17 @@ public final class DecoderVideoRendererTest {
|
|||
public void replaceStream_whenNotStarted_doesNotRenderFirstFrameOfNewStream() throws Exception {
|
||||
FakeSampleStream fakeSampleStream1 =
|
||||
new FakeSampleStream(
|
||||
/* mediaSourceEventDispatcher= */ null,
|
||||
DrmSessionManager.DUMMY,
|
||||
/* eventDispatcher= */ null,
|
||||
new DrmSessionEventListener.EventDispatcher(),
|
||||
/* initialFormat= */ H264_FORMAT,
|
||||
ImmutableList.of(
|
||||
oneByteSample(/* timeUs= */ 0), FakeSampleStreamItem.END_OF_STREAM_ITEM));
|
||||
FakeSampleStream fakeSampleStream2 =
|
||||
new FakeSampleStream(
|
||||
/* mediaSourceEventDispatcher= */ null,
|
||||
DrmSessionManager.DUMMY,
|
||||
/* eventDispatcher= */ null,
|
||||
new DrmSessionEventListener.EventDispatcher(),
|
||||
/* initialFormat= */ H264_FORMAT,
|
||||
ImmutableList.of(
|
||||
oneByteSample(/* timeUs= */ 0), FakeSampleStreamItem.END_OF_STREAM_ITEM));
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ import com.google.android.exoplayer2.Format;
|
|||
import com.google.android.exoplayer2.Renderer;
|
||||
import com.google.android.exoplayer2.RendererCapabilities;
|
||||
import com.google.android.exoplayer2.RendererConfiguration;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionEventListener;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.mediacodec.MediaCodecInfo;
|
||||
import com.google.android.exoplayer2.mediacodec.MediaCodecSelector;
|
||||
|
|
@ -129,8 +130,9 @@ public class MediaCodecVideoRendererTest {
|
|||
public void render_dropsLateBuffer() throws Exception {
|
||||
FakeSampleStream fakeSampleStream =
|
||||
new FakeSampleStream(
|
||||
/* mediaSourceEventDispatcher= */ null,
|
||||
DrmSessionManager.DUMMY,
|
||||
/* eventDispatcher= */ null,
|
||||
new DrmSessionEventListener.EventDispatcher(),
|
||||
/* initialFormat= */ VIDEO_H264,
|
||||
ImmutableList.of(
|
||||
oneByteSample(/* timeUs= */ 0, C.BUFFER_FLAG_KEY_FRAME), // First buffer.
|
||||
|
|
@ -165,8 +167,9 @@ public class MediaCodecVideoRendererTest {
|
|||
RendererConfiguration.DEFAULT,
|
||||
new Format[] {VIDEO_H264},
|
||||
new FakeSampleStream(
|
||||
/* mediaSourceEventDispatcher= */ null,
|
||||
DrmSessionManager.DUMMY,
|
||||
/* eventDispatcher= */ null,
|
||||
new DrmSessionEventListener.EventDispatcher(),
|
||||
/* initialFormat= */ VIDEO_H264,
|
||||
ImmutableList.of(
|
||||
oneByteSample(/* timeUs= */ 0, C.BUFFER_FLAG_KEY_FRAME),
|
||||
|
|
@ -202,8 +205,9 @@ public class MediaCodecVideoRendererTest {
|
|||
|
||||
FakeSampleStream fakeSampleStream =
|
||||
new FakeSampleStream(
|
||||
/* mediaSourceEventDispatcher= */ null,
|
||||
DrmSessionManager.DUMMY,
|
||||
/* eventDispatcher= */ null,
|
||||
new DrmSessionEventListener.EventDispatcher(),
|
||||
/* initialFormat= */ pAsp1,
|
||||
ImmutableList.of(oneByteSample(/* timeUs= */ 0, C.BUFFER_FLAG_KEY_FRAME)));
|
||||
|
||||
|
|
@ -246,8 +250,9 @@ public class MediaCodecVideoRendererTest {
|
|||
throws Exception {
|
||||
FakeSampleStream fakeSampleStream =
|
||||
new FakeSampleStream(
|
||||
/* mediaSourceEventDispatcher= */ null,
|
||||
DrmSessionManager.DUMMY,
|
||||
/* eventDispatcher= */ null,
|
||||
new DrmSessionEventListener.EventDispatcher(),
|
||||
/* initialFormat= */ VIDEO_H264,
|
||||
ImmutableList.of(oneByteSample(/* timeUs= */ 0, C.BUFFER_FLAG_KEY_FRAME)));
|
||||
mediaCodecVideoRenderer.enable(
|
||||
|
|
@ -279,8 +284,9 @@ public class MediaCodecVideoRendererTest {
|
|||
public void enable_withMayRenderStartOfStream_rendersFirstFrameBeforeStart() throws Exception {
|
||||
FakeSampleStream fakeSampleStream =
|
||||
new FakeSampleStream(
|
||||
/* mediaSourceEventDispatcher= */ null,
|
||||
DrmSessionManager.DUMMY,
|
||||
/* eventDispatcher= */ null,
|
||||
new DrmSessionEventListener.EventDispatcher(),
|
||||
/* initialFormat= */ VIDEO_H264,
|
||||
ImmutableList.of(oneByteSample(/* timeUs= */ 0, C.BUFFER_FLAG_KEY_FRAME)));
|
||||
|
||||
|
|
@ -304,8 +310,9 @@ public class MediaCodecVideoRendererTest {
|
|||
throws Exception {
|
||||
FakeSampleStream fakeSampleStream =
|
||||
new FakeSampleStream(
|
||||
/* mediaSourceEventDispatcher= */ null,
|
||||
DrmSessionManager.DUMMY,
|
||||
/* eventDispatcher= */ null,
|
||||
new DrmSessionEventListener.EventDispatcher(),
|
||||
/* initialFormat= */ VIDEO_H264,
|
||||
ImmutableList.of(oneByteSample(/* timeUs= */ 0)));
|
||||
|
||||
|
|
@ -328,8 +335,9 @@ public class MediaCodecVideoRendererTest {
|
|||
public void enable_withoutMayRenderStartOfStream_rendersFirstFrameAfterStart() throws Exception {
|
||||
FakeSampleStream fakeSampleStream =
|
||||
new FakeSampleStream(
|
||||
/* mediaSourceEventDispatcher= */ null,
|
||||
DrmSessionManager.DUMMY,
|
||||
/* eventDispatcher= */ null,
|
||||
new DrmSessionEventListener.EventDispatcher(),
|
||||
/* initialFormat= */ VIDEO_H264,
|
||||
ImmutableList.of(oneByteSample(/* timeUs= */ 0, C.BUFFER_FLAG_KEY_FRAME)));
|
||||
|
||||
|
|
@ -353,16 +361,18 @@ public class MediaCodecVideoRendererTest {
|
|||
public void replaceStream_whenStarted_rendersFirstFrameOfNewStream() throws Exception {
|
||||
FakeSampleStream fakeSampleStream1 =
|
||||
new FakeSampleStream(
|
||||
/* mediaSourceEventDispatcher= */ null,
|
||||
DrmSessionManager.DUMMY,
|
||||
/* eventDispatcher= */ null,
|
||||
new DrmSessionEventListener.EventDispatcher(),
|
||||
/* initialFormat= */ VIDEO_H264,
|
||||
ImmutableList.of(
|
||||
oneByteSample(/* timeUs= */ 0, C.BUFFER_FLAG_KEY_FRAME),
|
||||
FakeSampleStreamItem.END_OF_STREAM_ITEM));
|
||||
FakeSampleStream fakeSampleStream2 =
|
||||
new FakeSampleStream(
|
||||
/* mediaSourceEventDispatcher= */ null,
|
||||
DrmSessionManager.DUMMY,
|
||||
/* eventDispatcher= */ null,
|
||||
new DrmSessionEventListener.EventDispatcher(),
|
||||
/* initialFormat= */ VIDEO_H264,
|
||||
ImmutableList.of(
|
||||
oneByteSample(/* timeUs= */ 0, C.BUFFER_FLAG_KEY_FRAME),
|
||||
|
|
@ -395,16 +405,18 @@ public class MediaCodecVideoRendererTest {
|
|||
public void replaceStream_whenNotStarted_doesNotRenderFirstFrameOfNewStream() throws Exception {
|
||||
FakeSampleStream fakeSampleStream1 =
|
||||
new FakeSampleStream(
|
||||
/* mediaSourceEventDispatcher= */ null,
|
||||
DrmSessionManager.DUMMY,
|
||||
/* eventDispatcher= */ null,
|
||||
new DrmSessionEventListener.EventDispatcher(),
|
||||
/* initialFormat= */ VIDEO_H264,
|
||||
ImmutableList.of(
|
||||
oneByteSample(/* timeUs= */ 0, C.BUFFER_FLAG_KEY_FRAME),
|
||||
FakeSampleStreamItem.END_OF_STREAM_ITEM));
|
||||
FakeSampleStream fakeSampleStream2 =
|
||||
new FakeSampleStream(
|
||||
/* mediaSourceEventDispatcher= */ null,
|
||||
DrmSessionManager.DUMMY,
|
||||
/* eventDispatcher= */ null,
|
||||
new DrmSessionEventListener.EventDispatcher(),
|
||||
/* initialFormat= */ VIDEO_H264,
|
||||
ImmutableList.of(
|
||||
oneByteSample(/* timeUs= */ 0, C.BUFFER_FLAG_KEY_FRAME),
|
||||
|
|
@ -443,8 +455,9 @@ public class MediaCodecVideoRendererTest {
|
|||
Format mp4Uhd = VIDEO_H264.buildUpon().setWidth(3840).setHeight(2160).build();
|
||||
FakeSampleStream fakeSampleStream =
|
||||
new FakeSampleStream(
|
||||
/* mediaSourceEventDispatcher= */ null,
|
||||
DrmSessionManager.DUMMY,
|
||||
/* eventDispatcher= */ null,
|
||||
new DrmSessionEventListener.EventDispatcher(),
|
||||
/* initialFormat= */ mp4Uhd,
|
||||
ImmutableList.of(
|
||||
oneByteSample(/* timeUs= */ 0, C.BUFFER_FLAG_KEY_FRAME),
|
||||
|
|
|
|||
|
|
@ -24,11 +24,13 @@ import com.google.android.exoplayer2.C;
|
|||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.SeekParameters;
|
||||
import com.google.android.exoplayer2.drm.DrmInitData;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionEventListener;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.offline.StreamKey;
|
||||
import com.google.android.exoplayer2.source.CompositeSequenceableLoaderFactory;
|
||||
import com.google.android.exoplayer2.source.EmptySampleStream;
|
||||
import com.google.android.exoplayer2.source.MediaPeriod;
|
||||
import com.google.android.exoplayer2.source.MediaSourceEventListener;
|
||||
import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher;
|
||||
import com.google.android.exoplayer2.source.SampleStream;
|
||||
import com.google.android.exoplayer2.source.SequenceableLoader;
|
||||
|
|
@ -90,7 +92,8 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||
private final PlayerEmsgHandler playerEmsgHandler;
|
||||
private final IdentityHashMap<ChunkSampleStream<DashChunkSource>, PlayerTrackEmsgHandler>
|
||||
trackEmsgHandlerBySampleStream;
|
||||
private final EventDispatcher eventDispatcher;
|
||||
private final MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher;
|
||||
private final DrmSessionEventListener.EventDispatcher drmEventDispatcher;
|
||||
|
||||
@Nullable private Callback callback;
|
||||
private ChunkSampleStream<DashChunkSource>[] sampleStreams;
|
||||
|
|
@ -108,8 +111,9 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||
DashChunkSource.Factory chunkSourceFactory,
|
||||
@Nullable TransferListener transferListener,
|
||||
DrmSessionManager drmSessionManager,
|
||||
DrmSessionEventListener.EventDispatcher drmEventDispatcher,
|
||||
LoadErrorHandlingPolicy loadErrorHandlingPolicy,
|
||||
EventDispatcher eventDispatcher,
|
||||
EventDispatcher mediaSourceEventDispatcher,
|
||||
long elapsedRealtimeOffsetMs,
|
||||
LoaderErrorThrower manifestLoaderErrorThrower,
|
||||
Allocator allocator,
|
||||
|
|
@ -121,8 +125,9 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||
this.chunkSourceFactory = chunkSourceFactory;
|
||||
this.transferListener = transferListener;
|
||||
this.drmSessionManager = drmSessionManager;
|
||||
this.drmEventDispatcher = drmEventDispatcher;
|
||||
this.loadErrorHandlingPolicy = loadErrorHandlingPolicy;
|
||||
this.eventDispatcher = eventDispatcher;
|
||||
this.mediaSourceEventDispatcher = mediaSourceEventDispatcher;
|
||||
this.elapsedRealtimeOffsetMs = elapsedRealtimeOffsetMs;
|
||||
this.manifestLoaderErrorThrower = manifestLoaderErrorThrower;
|
||||
this.allocator = allocator;
|
||||
|
|
@ -139,7 +144,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||
buildTrackGroups(drmSessionManager, period.adaptationSets, eventStreams);
|
||||
trackGroups = result.first;
|
||||
trackGroupInfos = result.second;
|
||||
eventDispatcher.mediaPeriodCreated();
|
||||
mediaSourceEventDispatcher.mediaPeriodCreated();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -178,7 +183,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||
sampleStream.release(this);
|
||||
}
|
||||
callback = null;
|
||||
eventDispatcher.mediaPeriodReleased();
|
||||
mediaSourceEventDispatcher.mediaPeriodReleased();
|
||||
}
|
||||
|
||||
// ChunkSampleStream.ReleaseCallback implementation.
|
||||
|
|
@ -316,7 +321,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||
@Override
|
||||
public long readDiscontinuity() {
|
||||
if (!notifiedReadingStarted) {
|
||||
eventDispatcher.readingStarted();
|
||||
mediaSourceEventDispatcher.readingStarted();
|
||||
notifiedReadingStarted = true;
|
||||
}
|
||||
return C.TIME_UNSET;
|
||||
|
|
@ -788,8 +793,9 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||
allocator,
|
||||
positionUs,
|
||||
drmSessionManager,
|
||||
drmEventDispatcher,
|
||||
loadErrorHandlingPolicy,
|
||||
eventDispatcher);
|
||||
mediaSourceEventDispatcher);
|
||||
synchronized (this) {
|
||||
// The map is also accessed on the loading thread so synchronize access.
|
||||
trackEmsgHandlerBySampleStream.put(stream, trackPlayerEmsgHandler);
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import com.google.android.exoplayer2.MediaItem;
|
|||
import com.google.android.exoplayer2.ParserException;
|
||||
import com.google.android.exoplayer2.Timeline;
|
||||
import com.google.android.exoplayer2.drm.DrmSession;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionEventListener;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.offline.FilteringManifestParser;
|
||||
import com.google.android.exoplayer2.offline.StreamKey;
|
||||
|
|
@ -694,8 +695,9 @@ public final class DashMediaSource extends BaseMediaSource {
|
|||
public MediaPeriod createPeriod(
|
||||
MediaPeriodId periodId, Allocator allocator, long startPositionUs) {
|
||||
int periodIndex = (Integer) periodId.periodUid - firstPeriodId;
|
||||
EventDispatcher periodEventDispatcher =
|
||||
MediaSourceEventListener.EventDispatcher periodEventDispatcher =
|
||||
createEventDispatcher(periodId, manifest.getPeriod(periodIndex).startMs);
|
||||
DrmSessionEventListener.EventDispatcher drmEventDispatcher = createDrmEventDispatcher(periodId);
|
||||
DashMediaPeriod mediaPeriod =
|
||||
new DashMediaPeriod(
|
||||
firstPeriodId + periodIndex,
|
||||
|
|
@ -704,6 +706,7 @@ public final class DashMediaSource extends BaseMediaSource {
|
|||
chunkSourceFactory,
|
||||
mediaTransferListener,
|
||||
drmSessionManager,
|
||||
drmEventDispatcher,
|
||||
loadErrorHandlingPolicy,
|
||||
periodEventDispatcher,
|
||||
elapsedRealtimeOffsetMs,
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ import com.google.android.exoplayer2.C;
|
|||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.FormatHolder;
|
||||
import com.google.android.exoplayer2.ParserException;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionEventListener;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.extractor.TrackOutput;
|
||||
import com.google.android.exoplayer2.metadata.Metadata;
|
||||
|
|
@ -35,7 +36,6 @@ import com.google.android.exoplayer2.source.chunk.Chunk;
|
|||
import com.google.android.exoplayer2.source.dash.manifest.DashManifest;
|
||||
import com.google.android.exoplayer2.upstream.Allocator;
|
||||
import com.google.android.exoplayer2.upstream.DataReader;
|
||||
import com.google.android.exoplayer2.util.MediaSourceEventDispatcher;
|
||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.io.IOException;
|
||||
|
|
@ -290,7 +290,7 @@ public final class PlayerEmsgHandler implements Handler.Callback {
|
|||
allocator,
|
||||
/* playbackLooper= */ handler.getLooper(),
|
||||
DrmSessionManager.getDummyDrmSessionManager(),
|
||||
new MediaSourceEventDispatcher());
|
||||
new DrmSessionEventListener.EventDispatcher());
|
||||
formatHolder = new FormatHolder();
|
||||
buffer = new MetadataInputBuffer();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,10 +22,11 @@ import androidx.annotation.Nullable;
|
|||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionEventListener;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.source.CompositeSequenceableLoaderFactory;
|
||||
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
|
||||
import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher;
|
||||
import com.google.android.exoplayer2.source.MediaSourceEventListener;
|
||||
import com.google.android.exoplayer2.source.TrackGroup;
|
||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||
import com.google.android.exoplayer2.source.dash.PlayerEmsgHandler.PlayerEmsgCallback;
|
||||
|
|
@ -344,6 +345,7 @@ public final class DashMediaPeriodTest {
|
|||
}
|
||||
|
||||
private static DashMediaPeriod createDashMediaPeriod(DashManifest manifest, int periodIndex) {
|
||||
MediaPeriodId mediaPeriodId = new MediaPeriodId(/* periodUid= */ new Object());
|
||||
return new DashMediaPeriod(
|
||||
/* id= */ periodIndex,
|
||||
manifest,
|
||||
|
|
@ -351,12 +353,11 @@ public final class DashMediaPeriodTest {
|
|||
mock(DashChunkSource.Factory.class),
|
||||
mock(TransferListener.class),
|
||||
DrmSessionManager.getDummyDrmSessionManager(),
|
||||
new DrmSessionEventListener.EventDispatcher()
|
||||
.withParameters(/* windowIndex= */ 0, mediaPeriodId),
|
||||
mock(LoadErrorHandlingPolicy.class),
|
||||
new EventDispatcher()
|
||||
.withParameters(
|
||||
/* windowIndex= */ 0,
|
||||
/* mediaPeriodId= */ new MediaPeriodId(/* periodUid= */ new Object()),
|
||||
/* mediaTimeOffsetMs= */ 0),
|
||||
new MediaSourceEventListener.EventDispatcher()
|
||||
.withParameters(/* windowIndex= */ 0, mediaPeriodId, /* mediaTimeOffsetMs= */ 0),
|
||||
/* elapsedRealtimeOffsetMs= */ 0,
|
||||
mock(LoaderErrorThrower.class),
|
||||
mock(Allocator.class),
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import com.google.android.exoplayer2.Format;
|
|||
import com.google.android.exoplayer2.SeekParameters;
|
||||
import com.google.android.exoplayer2.drm.DrmInitData;
|
||||
import com.google.android.exoplayer2.drm.DrmSession;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionEventListener;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.extractor.Extractor;
|
||||
import com.google.android.exoplayer2.metadata.Metadata;
|
||||
|
|
@ -69,6 +70,7 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
|
|||
private final HlsDataSourceFactory dataSourceFactory;
|
||||
@Nullable private final TransferListener mediaTransferListener;
|
||||
private final DrmSessionManager drmSessionManager;
|
||||
private final DrmSessionEventListener.EventDispatcher drmEventDispatcher;
|
||||
private final LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
||||
private final EventDispatcher eventDispatcher;
|
||||
private final Allocator allocator;
|
||||
|
|
@ -114,6 +116,7 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
|
|||
HlsDataSourceFactory dataSourceFactory,
|
||||
@Nullable TransferListener mediaTransferListener,
|
||||
DrmSessionManager drmSessionManager,
|
||||
DrmSessionEventListener.EventDispatcher drmEventDispatcher,
|
||||
LoadErrorHandlingPolicy loadErrorHandlingPolicy,
|
||||
EventDispatcher eventDispatcher,
|
||||
Allocator allocator,
|
||||
|
|
@ -126,6 +129,7 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
|
|||
this.dataSourceFactory = dataSourceFactory;
|
||||
this.mediaTransferListener = mediaTransferListener;
|
||||
this.drmSessionManager = drmSessionManager;
|
||||
this.drmEventDispatcher = drmEventDispatcher;
|
||||
this.loadErrorHandlingPolicy = loadErrorHandlingPolicy;
|
||||
this.eventDispatcher = eventDispatcher;
|
||||
this.allocator = allocator;
|
||||
|
|
@ -758,6 +762,7 @@ public final class HlsMediaPeriod implements MediaPeriod, HlsSampleStreamWrapper
|
|||
positionUs,
|
||||
muxedAudioFormat,
|
||||
drmSessionManager,
|
||||
drmEventDispatcher,
|
||||
loadErrorHandlingPolicy,
|
||||
eventDispatcher,
|
||||
metadataType);
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import com.google.android.exoplayer2.C;
|
|||
import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
|
||||
import com.google.android.exoplayer2.MediaItem;
|
||||
import com.google.android.exoplayer2.drm.DrmSession;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionEventListener;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.extractor.Extractor;
|
||||
import com.google.android.exoplayer2.offline.StreamKey;
|
||||
|
|
@ -35,7 +36,6 @@ import com.google.android.exoplayer2.source.DefaultCompositeSequenceableLoaderFa
|
|||
import com.google.android.exoplayer2.source.MediaPeriod;
|
||||
import com.google.android.exoplayer2.source.MediaSource;
|
||||
import com.google.android.exoplayer2.source.MediaSourceEventListener;
|
||||
import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher;
|
||||
import com.google.android.exoplayer2.source.MediaSourceFactory;
|
||||
import com.google.android.exoplayer2.source.SequenceableLoader;
|
||||
import com.google.android.exoplayer2.source.SinglePeriodTimeline;
|
||||
|
|
@ -446,7 +446,8 @@ public final class HlsMediaSource extends BaseMediaSource
|
|||
protected void prepareSourceInternal(@Nullable TransferListener mediaTransferListener) {
|
||||
this.mediaTransferListener = mediaTransferListener;
|
||||
drmSessionManager.prepare();
|
||||
EventDispatcher eventDispatcher = createEventDispatcher(/* mediaPeriodId= */ null);
|
||||
MediaSourceEventListener.EventDispatcher eventDispatcher =
|
||||
createEventDispatcher(/* mediaPeriodId= */ null);
|
||||
playlistTracker.start(playbackProperties.uri, eventDispatcher, /* listener= */ this);
|
||||
}
|
||||
|
||||
|
|
@ -457,15 +458,17 @@ public final class HlsMediaSource extends BaseMediaSource
|
|||
|
||||
@Override
|
||||
public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator, long startPositionUs) {
|
||||
EventDispatcher eventDispatcher = createEventDispatcher(id);
|
||||
MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher = createEventDispatcher(id);
|
||||
DrmSessionEventListener.EventDispatcher drmEventDispatcher = createDrmEventDispatcher(id);
|
||||
return new HlsMediaPeriod(
|
||||
extractorFactory,
|
||||
playlistTracker,
|
||||
dataSourceFactory,
|
||||
mediaTransferListener,
|
||||
drmSessionManager,
|
||||
drmEventDispatcher,
|
||||
loadErrorHandlingPolicy,
|
||||
eventDispatcher,
|
||||
mediaSourceEventDispatcher,
|
||||
allocator,
|
||||
compositeSequenceableLoaderFactory,
|
||||
allowChunklessPreparation,
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import com.google.android.exoplayer2.ParserException;
|
|||
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
|
||||
import com.google.android.exoplayer2.drm.DrmInitData;
|
||||
import com.google.android.exoplayer2.drm.DrmSession;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionEventListener;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.extractor.DummyTrackOutput;
|
||||
import com.google.android.exoplayer2.extractor.Extractor;
|
||||
|
|
@ -39,7 +40,7 @@ import com.google.android.exoplayer2.metadata.emsg.EventMessageDecoder;
|
|||
import com.google.android.exoplayer2.metadata.id3.PrivFrame;
|
||||
import com.google.android.exoplayer2.source.LoadEventInfo;
|
||||
import com.google.android.exoplayer2.source.MediaLoadData;
|
||||
import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher;
|
||||
import com.google.android.exoplayer2.source.MediaSourceEventListener;
|
||||
import com.google.android.exoplayer2.source.SampleQueue;
|
||||
import com.google.android.exoplayer2.source.SampleQueue.UpstreamFormatChangedListener;
|
||||
import com.google.android.exoplayer2.source.SampleStream;
|
||||
|
|
@ -57,7 +58,6 @@ import com.google.android.exoplayer2.upstream.Loader;
|
|||
import com.google.android.exoplayer2.upstream.Loader.LoadErrorAction;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Log;
|
||||
import com.google.android.exoplayer2.util.MediaSourceEventDispatcher;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
import com.google.android.exoplayer2.util.ParsableByteArray;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
|
|
@ -120,9 +120,10 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||
private final Allocator allocator;
|
||||
@Nullable private final Format muxedAudioFormat;
|
||||
private final DrmSessionManager drmSessionManager;
|
||||
private final DrmSessionEventListener.EventDispatcher drmEventDispatcher;
|
||||
private final LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
||||
private final Loader loader;
|
||||
private final EventDispatcher eventDispatcher;
|
||||
private final MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher;
|
||||
private final @HlsMediaSource.MetadataType int metadataType;
|
||||
private final HlsChunkSource.HlsChunkHolder nextChunkHolder;
|
||||
private final ArrayList<HlsMediaChunk> mediaChunks;
|
||||
|
|
@ -185,8 +186,10 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||
* @param muxedAudioFormat Optional muxed audio {@link Format} as defined by the master playlist.
|
||||
* @param drmSessionManager The {@link DrmSessionManager} to acquire {@link DrmSession
|
||||
* DrmSessions} with.
|
||||
* @param drmEventDispatcher A dispatcher to notify of {@link DrmSessionEventListener} events.
|
||||
* @param loadErrorHandlingPolicy A {@link LoadErrorHandlingPolicy}.
|
||||
* @param eventDispatcher A dispatcher to notify of events.
|
||||
* @param mediaSourceEventDispatcher A dispatcher to notify of {@link MediaSourceEventListener}
|
||||
* events.
|
||||
*/
|
||||
public HlsSampleStreamWrapper(
|
||||
int trackType,
|
||||
|
|
@ -197,8 +200,9 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||
long positionUs,
|
||||
@Nullable Format muxedAudioFormat,
|
||||
DrmSessionManager drmSessionManager,
|
||||
DrmSessionEventListener.EventDispatcher drmEventDispatcher,
|
||||
LoadErrorHandlingPolicy loadErrorHandlingPolicy,
|
||||
EventDispatcher eventDispatcher,
|
||||
MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher,
|
||||
@HlsMediaSource.MetadataType int metadataType) {
|
||||
this.trackType = trackType;
|
||||
this.callback = callback;
|
||||
|
|
@ -207,8 +211,9 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||
this.allocator = allocator;
|
||||
this.muxedAudioFormat = muxedAudioFormat;
|
||||
this.drmSessionManager = drmSessionManager;
|
||||
this.drmEventDispatcher = drmEventDispatcher;
|
||||
this.loadErrorHandlingPolicy = loadErrorHandlingPolicy;
|
||||
this.eventDispatcher = eventDispatcher;
|
||||
this.mediaSourceEventDispatcher = mediaSourceEventDispatcher;
|
||||
this.metadataType = metadataType;
|
||||
loader = new Loader("Loader:HlsSampleStreamWrapper");
|
||||
nextChunkHolder = new HlsChunkSource.HlsChunkHolder();
|
||||
|
|
@ -552,8 +557,11 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||
HlsMediaChunk currentChunk = mediaChunks.get(0);
|
||||
Format trackFormat = currentChunk.trackFormat;
|
||||
if (!trackFormat.equals(downstreamTrackFormat)) {
|
||||
eventDispatcher.downstreamFormatChanged(trackType, trackFormat,
|
||||
currentChunk.trackSelectionReason, currentChunk.trackSelectionData,
|
||||
mediaSourceEventDispatcher.downstreamFormatChanged(
|
||||
trackType,
|
||||
trackFormat,
|
||||
currentChunk.trackSelectionReason,
|
||||
currentChunk.trackSelectionData,
|
||||
currentChunk.startTimeUs);
|
||||
}
|
||||
downstreamTrackFormat = trackFormat;
|
||||
|
|
@ -682,7 +690,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||
long elapsedRealtimeMs =
|
||||
loader.startLoading(
|
||||
loadable, this, loadErrorHandlingPolicy.getMinimumLoadableRetryCount(loadable.type));
|
||||
eventDispatcher.loadStarted(
|
||||
mediaSourceEventDispatcher.loadStarted(
|
||||
new LoadEventInfo(loadable.loadTaskId, loadable.dataSpec, elapsedRealtimeMs),
|
||||
loadable.type,
|
||||
trackType,
|
||||
|
|
@ -735,7 +743,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||
loadDurationMs,
|
||||
loadable.bytesLoaded());
|
||||
loadErrorHandlingPolicy.onLoadTaskConcluded(loadable.loadTaskId);
|
||||
eventDispatcher.loadCompleted(
|
||||
mediaSourceEventDispatcher.loadCompleted(
|
||||
loadEventInfo,
|
||||
loadable.type,
|
||||
trackType,
|
||||
|
|
@ -765,7 +773,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||
loadDurationMs,
|
||||
loadable.bytesLoaded());
|
||||
loadErrorHandlingPolicy.onLoadTaskConcluded(loadable.loadTaskId);
|
||||
eventDispatcher.loadCanceled(
|
||||
mediaSourceEventDispatcher.loadCanceled(
|
||||
loadEventInfo,
|
||||
loadable.type,
|
||||
trackType,
|
||||
|
|
@ -838,7 +846,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||
}
|
||||
|
||||
boolean wasCanceled = !loadErrorAction.isRetry();
|
||||
eventDispatcher.loadError(
|
||||
mediaSourceEventDispatcher.loadError(
|
||||
loadEventInfo,
|
||||
loadable.type,
|
||||
trackType,
|
||||
|
|
@ -910,7 +918,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||
}
|
||||
loadingFinished = false;
|
||||
|
||||
eventDispatcher.upstreamDiscarded(
|
||||
mediaSourceEventDispatcher.upstreamDiscarded(
|
||||
primarySampleQueueType, firstRemovedChunk.startTimeUs, endTimeUs);
|
||||
}
|
||||
|
||||
|
|
@ -989,7 +997,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||
allocator,
|
||||
/* playbackLooper= */ handler.getLooper(),
|
||||
drmSessionManager,
|
||||
eventDispatcher,
|
||||
drmEventDispatcher,
|
||||
overridingDrmInitData);
|
||||
if (isAudioVideo) {
|
||||
sampleQueue.setDrmInitData(drmInitData);
|
||||
|
|
@ -1496,7 +1504,7 @@ import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
|||
Allocator allocator,
|
||||
Looper playbackLooper,
|
||||
DrmSessionManager drmSessionManager,
|
||||
MediaSourceEventDispatcher eventDispatcher,
|
||||
DrmSessionEventListener.EventDispatcher eventDispatcher,
|
||||
Map<String, DrmInitData> overridingDrmInitData) {
|
||||
super(allocator, playbackLooper, drmSessionManager, eventDispatcher);
|
||||
this.overridingDrmInitData = overridingDrmInitData;
|
||||
|
|
|
|||
|
|
@ -22,10 +22,11 @@ import static org.mockito.Mockito.when;
|
|||
import android.net.Uri;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionEventListener;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.source.CompositeSequenceableLoaderFactory;
|
||||
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
|
||||
import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher;
|
||||
import com.google.android.exoplayer2.source.MediaSourceEventListener;
|
||||
import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist;
|
||||
import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist.Rendition;
|
||||
import com.google.android.exoplayer2.source.hls.playlist.HlsMasterPlaylist.Variant;
|
||||
|
|
@ -77,18 +78,18 @@ public final class HlsMediaPeriodTest {
|
|||
when(mockDataSourceFactory.createDataSource(anyInt())).thenReturn(mock(DataSource.class));
|
||||
HlsPlaylistTracker mockPlaylistTracker = mock(HlsPlaylistTracker.class);
|
||||
when(mockPlaylistTracker.getMasterPlaylist()).thenReturn((HlsMasterPlaylist) playlist);
|
||||
MediaPeriodId mediaPeriodId = new MediaPeriodId(/* periodUid= */ new Object());
|
||||
return new HlsMediaPeriod(
|
||||
mock(HlsExtractorFactory.class),
|
||||
mockPlaylistTracker,
|
||||
mockDataSourceFactory,
|
||||
mock(TransferListener.class),
|
||||
mock(DrmSessionManager.class),
|
||||
new DrmSessionEventListener.EventDispatcher()
|
||||
.withParameters(/* windowIndex= */ 0, mediaPeriodId),
|
||||
mock(LoadErrorHandlingPolicy.class),
|
||||
new EventDispatcher()
|
||||
.withParameters(
|
||||
/* windowIndex= */ 0,
|
||||
/* mediaPeriodId= */ new MediaPeriodId(/* periodUid= */ new Object()),
|
||||
/* mediaTimeOffsetMs= */ 0),
|
||||
new MediaSourceEventListener.EventDispatcher()
|
||||
.withParameters(/* windowIndex= */ 0, mediaPeriodId, /* mediaTimeOffsetMs= */ 0),
|
||||
mock(Allocator.class),
|
||||
mock(CompositeSequenceableLoaderFactory.class),
|
||||
/* allowChunklessPreparation =*/ true,
|
||||
|
|
|
|||
|
|
@ -19,11 +19,12 @@ import androidx.annotation.Nullable;
|
|||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.SeekParameters;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionEventListener;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.offline.StreamKey;
|
||||
import com.google.android.exoplayer2.source.CompositeSequenceableLoaderFactory;
|
||||
import com.google.android.exoplayer2.source.MediaPeriod;
|
||||
import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher;
|
||||
import com.google.android.exoplayer2.source.MediaSourceEventListener;
|
||||
import com.google.android.exoplayer2.source.SampleStream;
|
||||
import com.google.android.exoplayer2.source.SequenceableLoader;
|
||||
import com.google.android.exoplayer2.source.TrackGroup;
|
||||
|
|
@ -48,8 +49,9 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||
@Nullable private final TransferListener transferListener;
|
||||
private final LoaderErrorThrower manifestLoaderErrorThrower;
|
||||
private final DrmSessionManager drmSessionManager;
|
||||
private final DrmSessionEventListener.EventDispatcher drmEventDispatcher;
|
||||
private final LoadErrorHandlingPolicy loadErrorHandlingPolicy;
|
||||
private final EventDispatcher eventDispatcher;
|
||||
private final MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher;
|
||||
private final Allocator allocator;
|
||||
private final TrackGroupArray trackGroups;
|
||||
private final CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory;
|
||||
|
|
@ -66,8 +68,9 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||
@Nullable TransferListener transferListener,
|
||||
CompositeSequenceableLoaderFactory compositeSequenceableLoaderFactory,
|
||||
DrmSessionManager drmSessionManager,
|
||||
DrmSessionEventListener.EventDispatcher drmEventDispatcher,
|
||||
LoadErrorHandlingPolicy loadErrorHandlingPolicy,
|
||||
EventDispatcher eventDispatcher,
|
||||
MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher,
|
||||
LoaderErrorThrower manifestLoaderErrorThrower,
|
||||
Allocator allocator) {
|
||||
this.manifest = manifest;
|
||||
|
|
@ -75,15 +78,16 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||
this.transferListener = transferListener;
|
||||
this.manifestLoaderErrorThrower = manifestLoaderErrorThrower;
|
||||
this.drmSessionManager = drmSessionManager;
|
||||
this.drmEventDispatcher = drmEventDispatcher;
|
||||
this.loadErrorHandlingPolicy = loadErrorHandlingPolicy;
|
||||
this.eventDispatcher = eventDispatcher;
|
||||
this.mediaSourceEventDispatcher = mediaSourceEventDispatcher;
|
||||
this.allocator = allocator;
|
||||
this.compositeSequenceableLoaderFactory = compositeSequenceableLoaderFactory;
|
||||
trackGroups = buildTrackGroups(manifest, drmSessionManager);
|
||||
sampleStreams = newSampleStreamArray(0);
|
||||
compositeSequenceableLoader =
|
||||
compositeSequenceableLoaderFactory.createCompositeSequenceableLoader(sampleStreams);
|
||||
eventDispatcher.mediaPeriodCreated();
|
||||
mediaSourceEventDispatcher.mediaPeriodCreated();
|
||||
}
|
||||
|
||||
public void updateManifest(SsManifest manifest) {
|
||||
|
|
@ -99,7 +103,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||
sampleStream.release();
|
||||
}
|
||||
callback = null;
|
||||
eventDispatcher.mediaPeriodReleased();
|
||||
mediaSourceEventDispatcher.mediaPeriodReleased();
|
||||
}
|
||||
|
||||
// MediaPeriod implementation.
|
||||
|
|
@ -197,7 +201,7 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||
@Override
|
||||
public long readDiscontinuity() {
|
||||
if (!notifiedReadingStarted) {
|
||||
eventDispatcher.readingStarted();
|
||||
mediaSourceEventDispatcher.readingStarted();
|
||||
notifiedReadingStarted = true;
|
||||
}
|
||||
return C.TIME_UNSET;
|
||||
|
|
@ -254,8 +258,9 @@ import org.checkerframework.checker.nullness.compatqual.NullableType;
|
|||
allocator,
|
||||
positionUs,
|
||||
drmSessionManager,
|
||||
drmEventDispatcher,
|
||||
loadErrorHandlingPolicy,
|
||||
eventDispatcher);
|
||||
mediaSourceEventDispatcher);
|
||||
}
|
||||
|
||||
private static TrackGroupArray buildTrackGroups(
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import com.google.android.exoplayer2.ExoPlayerLibraryInfo;
|
|||
import com.google.android.exoplayer2.MediaItem;
|
||||
import com.google.android.exoplayer2.Timeline;
|
||||
import com.google.android.exoplayer2.drm.DrmSession;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionEventListener;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.offline.FilteringManifestParser;
|
||||
import com.google.android.exoplayer2.offline.StreamKey;
|
||||
|
|
@ -632,7 +633,8 @@ public final class SsMediaSource extends BaseMediaSource
|
|||
|
||||
@Override
|
||||
public MediaPeriod createPeriod(MediaPeriodId id, Allocator allocator, long startPositionUs) {
|
||||
EventDispatcher eventDispatcher = createEventDispatcher(id);
|
||||
MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher = createEventDispatcher(id);
|
||||
DrmSessionEventListener.EventDispatcher drmEventDispatcher = createDrmEventDispatcher(id);
|
||||
SsMediaPeriod period =
|
||||
new SsMediaPeriod(
|
||||
manifest,
|
||||
|
|
@ -640,8 +642,9 @@ public final class SsMediaSource extends BaseMediaSource
|
|||
mediaTransferListener,
|
||||
compositeSequenceableLoaderFactory,
|
||||
drmSessionManager,
|
||||
drmEventDispatcher,
|
||||
loadErrorHandlingPolicy,
|
||||
eventDispatcher,
|
||||
mediaSourceEventDispatcher,
|
||||
manifestLoaderErrorThrower,
|
||||
allocator);
|
||||
mediaPeriods.add(period);
|
||||
|
|
|
|||
|
|
@ -22,10 +22,11 @@ import static org.mockito.Mockito.mock;
|
|||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionEventListener;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.source.CompositeSequenceableLoaderFactory;
|
||||
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
|
||||
import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher;
|
||||
import com.google.android.exoplayer2.source.MediaSourceEventListener;
|
||||
import com.google.android.exoplayer2.source.smoothstreaming.manifest.SsManifest;
|
||||
import com.google.android.exoplayer2.testutil.MediaPeriodAsserts;
|
||||
import com.google.android.exoplayer2.testutil.MediaPeriodAsserts.FilterableManifestMediaPeriodFactory;
|
||||
|
|
@ -61,21 +62,22 @@ public class SsMediaPeriodTest {
|
|||
createStreamElement(
|
||||
/* name= */ "text", C.TRACK_TYPE_TEXT, createTextFormat(/* language= */ "eng")));
|
||||
FilterableManifestMediaPeriodFactory<SsManifest> mediaPeriodFactory =
|
||||
(manifest, periodIndex) ->
|
||||
new SsMediaPeriod(
|
||||
manifest,
|
||||
mock(SsChunkSource.Factory.class),
|
||||
mock(TransferListener.class),
|
||||
mock(CompositeSequenceableLoaderFactory.class),
|
||||
mock(DrmSessionManager.class),
|
||||
mock(LoadErrorHandlingPolicy.class),
|
||||
new EventDispatcher()
|
||||
.withParameters(
|
||||
/* windowIndex= */ 0,
|
||||
/* mediaPeriodId= */ new MediaPeriodId(/* periodUid= */ new Object()),
|
||||
/* mediaTimeOffsetMs= */ 0),
|
||||
mock(LoaderErrorThrower.class),
|
||||
mock(Allocator.class));
|
||||
(manifest, periodIndex) -> {
|
||||
MediaPeriodId mediaPeriodId = new MediaPeriodId(/* periodUid= */ new Object());
|
||||
return new SsMediaPeriod(
|
||||
manifest,
|
||||
mock(SsChunkSource.Factory.class),
|
||||
mock(TransferListener.class),
|
||||
mock(CompositeSequenceableLoaderFactory.class),
|
||||
mock(DrmSessionManager.class),
|
||||
new DrmSessionEventListener.EventDispatcher()
|
||||
.withParameters(/* windowIndex= */ 0, mediaPeriodId),
|
||||
mock(LoadErrorHandlingPolicy.class),
|
||||
new MediaSourceEventListener.EventDispatcher()
|
||||
.withParameters(/* windowIndex= */ 0, mediaPeriodId, /* mediaTimeOffsetMs= */ 0),
|
||||
mock(LoaderErrorThrower.class),
|
||||
mock(Allocator.class));
|
||||
};
|
||||
|
||||
MediaPeriodAsserts.assertGetStreamKeysAndManifestFilterIntegration(
|
||||
mediaPeriodFactory, testManifest);
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import androidx.test.rule.ActivityTestRule;
|
|||
import com.google.android.exoplayer2.Player;
|
||||
import com.google.android.exoplayer2.drm.DrmInitData;
|
||||
import com.google.android.exoplayer2.drm.DrmSession.DrmSessionException;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionEventListener;
|
||||
import com.google.android.exoplayer2.drm.OfflineLicenseHelper;
|
||||
import com.google.android.exoplayer2.source.dash.DashUtil;
|
||||
import com.google.android.exoplayer2.source.dash.manifest.DashManifest;
|
||||
|
|
@ -34,7 +35,6 @@ import com.google.android.exoplayer2.testutil.ActionSchedule;
|
|||
import com.google.android.exoplayer2.testutil.HostActivity;
|
||||
import com.google.android.exoplayer2.upstream.DataSource;
|
||||
import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory;
|
||||
import com.google.android.exoplayer2.util.MediaSourceEventDispatcher;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.io.IOException;
|
||||
|
|
@ -77,7 +77,9 @@ public final class DashWidevineOfflineTest {
|
|||
if (Util.SDK_INT >= 18) {
|
||||
offlineLicenseHelper =
|
||||
OfflineLicenseHelper.newWidevineInstance(
|
||||
widevineLicenseUrl, httpDataSourceFactory, new MediaSourceEventDispatcher());
|
||||
widevineLicenseUrl,
|
||||
httpDataSourceFactory,
|
||||
new DrmSessionEventListener.EventDispatcher());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,10 +16,11 @@
|
|||
package com.google.android.exoplayer2.testutil;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionEventListener;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.source.CompositeSequenceableLoader;
|
||||
import com.google.android.exoplayer2.source.MediaPeriod;
|
||||
import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher;
|
||||
import com.google.android.exoplayer2.source.MediaSourceEventListener;
|
||||
import com.google.android.exoplayer2.source.SampleStream;
|
||||
import com.google.android.exoplayer2.source.SequenceableLoader;
|
||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||
|
|
@ -53,7 +54,7 @@ public class FakeAdaptiveMediaPeriod extends FakeMediaPeriod
|
|||
|
||||
public FakeAdaptiveMediaPeriod(
|
||||
TrackGroupArray trackGroupArray,
|
||||
EventDispatcher eventDispatcher,
|
||||
MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher,
|
||||
Allocator allocator,
|
||||
FakeChunkSource.Factory chunkSourceFactory,
|
||||
long durationUs,
|
||||
|
|
@ -63,8 +64,9 @@ public class FakeAdaptiveMediaPeriod extends FakeMediaPeriod
|
|||
/* trackDataFactory= */ (unusedFormat, unusedMediaPeriodId) -> {
|
||||
throw new RuntimeException("unused track data");
|
||||
},
|
||||
eventDispatcher,
|
||||
mediaSourceEventDispatcher,
|
||||
DrmSessionManager.DUMMY,
|
||||
new DrmSessionEventListener.EventDispatcher(),
|
||||
/* deferOnPrepared= */ false);
|
||||
this.allocator = allocator;
|
||||
this.chunkSourceFactory = chunkSourceFactory;
|
||||
|
|
@ -143,8 +145,9 @@ public class FakeAdaptiveMediaPeriod extends FakeMediaPeriod
|
|||
protected final SampleStream createSampleStream(
|
||||
long positionUs,
|
||||
TrackSelection trackSelection,
|
||||
MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher,
|
||||
DrmSessionManager drmSessionManager,
|
||||
EventDispatcher eventDispatcher) {
|
||||
DrmSessionEventListener.EventDispatcher drmEventDispatcher) {
|
||||
FakeChunkSource chunkSource =
|
||||
chunkSourceFactory.createChunkSource(trackSelection, durationUs, transferListener);
|
||||
return new ChunkSampleStream<>(
|
||||
|
|
@ -156,8 +159,9 @@ public class FakeAdaptiveMediaPeriod extends FakeMediaPeriod
|
|||
allocator,
|
||||
positionUs,
|
||||
/* drmSessionManager= */ DrmSessionManager.getDummyDrmSessionManager(),
|
||||
drmEventDispatcher,
|
||||
new DefaultLoadErrorHandlingPolicy(/* minimumLoadableRetryCount= */ 3),
|
||||
eventDispatcher);
|
||||
mediaSourceEventDispatcher);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -18,9 +18,10 @@ package com.google.android.exoplayer2.testutil;
|
|||
import androidx.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.Timeline;
|
||||
import com.google.android.exoplayer2.Timeline.Period;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionEventListener;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.source.MediaSource;
|
||||
import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher;
|
||||
import com.google.android.exoplayer2.source.MediaSourceEventListener;
|
||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||
import com.google.android.exoplayer2.upstream.Allocator;
|
||||
import com.google.android.exoplayer2.upstream.TransferListener;
|
||||
|
|
@ -53,13 +54,14 @@ public class FakeAdaptiveMediaSource extends FakeMediaSource {
|
|||
MediaPeriodId id,
|
||||
TrackGroupArray trackGroupArray,
|
||||
Allocator allocator,
|
||||
MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher,
|
||||
DrmSessionManager drmSessionManager,
|
||||
EventDispatcher eventDispatcher,
|
||||
DrmSessionEventListener.EventDispatcher drmEventDispatcher,
|
||||
@Nullable TransferListener transferListener) {
|
||||
Period period = Util.castNonNull(getTimeline()).getPeriodByUid(id.periodUid, new Period());
|
||||
return new FakeAdaptiveMediaPeriod(
|
||||
trackGroupArray,
|
||||
eventDispatcher,
|
||||
mediaSourceEventDispatcher,
|
||||
allocator,
|
||||
chunkSourceFactory,
|
||||
period.durationUs,
|
||||
|
|
|
|||
|
|
@ -26,11 +26,12 @@ import androidx.annotation.Nullable;
|
|||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.SeekParameters;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionEventListener;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.source.LoadEventInfo;
|
||||
import com.google.android.exoplayer2.source.MediaPeriod;
|
||||
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
|
||||
import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher;
|
||||
import com.google.android.exoplayer2.source.MediaSourceEventListener;
|
||||
import com.google.android.exoplayer2.source.SampleStream;
|
||||
import com.google.android.exoplayer2.source.TrackGroup;
|
||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||
|
|
@ -57,9 +58,10 @@ public class FakeMediaPeriod implements MediaPeriod {
|
|||
|
||||
private final TrackGroupArray trackGroupArray;
|
||||
private final List<SampleStream> sampleStreams;
|
||||
private final DrmSessionManager drmSessionManager;
|
||||
private final EventDispatcher eventDispatcher;
|
||||
private final TrackDataFactory trackDataFactory;
|
||||
private final MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher;
|
||||
private final DrmSessionManager drmSessionManager;
|
||||
private final DrmSessionEventListener.EventDispatcher drmEventDispatcher;
|
||||
private final long fakePreparationLoadTaskId;
|
||||
|
||||
@Nullable private Handler playerHandler;
|
||||
|
|
@ -77,16 +79,19 @@ public class FakeMediaPeriod implements MediaPeriod {
|
|||
* @param trackGroupArray The track group array.
|
||||
* @param singleSampleTimeUs The timestamp to use for the single sample in each track, in
|
||||
* microseconds.
|
||||
* @param eventDispatcher A dispatcher for media source events.
|
||||
* @param mediaSourceEventDispatcher A dispatcher for {@link MediaSourceEventListener} events.
|
||||
*/
|
||||
public FakeMediaPeriod(
|
||||
TrackGroupArray trackGroupArray, long singleSampleTimeUs, EventDispatcher eventDispatcher) {
|
||||
TrackGroupArray trackGroupArray,
|
||||
long singleSampleTimeUs,
|
||||
MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher) {
|
||||
this(
|
||||
trackGroupArray,
|
||||
TrackDataFactory.singleSampleWithTimeUs(singleSampleTimeUs),
|
||||
eventDispatcher,
|
||||
mediaSourceEventDispatcher,
|
||||
DrmSessionManager.DUMMY,
|
||||
/* deferOnPrepared= */ false);
|
||||
new DrmSessionEventListener.EventDispatcher(),
|
||||
/* deferOnPrepared */ false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -95,22 +100,26 @@ public class FakeMediaPeriod implements MediaPeriod {
|
|||
* @param trackGroupArray The track group array.
|
||||
* @param singleSampleTimeUs The timestamp to use for the single sample in each track, in
|
||||
* microseconds.
|
||||
* @param eventDispatcher A dispatcher for media source events.
|
||||
* @param mediaSourceEventDispatcher A dispatcher for {@link MediaSourceEventListener} events.
|
||||
* @param drmSessionManager The {@link DrmSessionManager} used for DRM interactions.
|
||||
* @param drmEventDispatcher A dispatcher for {@link DrmSessionEventListener} events.
|
||||
* @param deferOnPrepared Whether {@link Callback#onPrepared(MediaPeriod)} should be called only
|
||||
* after {@link #setPreparationComplete()} has been called. If {@code false}
|
||||
* after {@link #setPreparationComplete()} has been called. If {@code false} preparation
|
||||
* completes immediately.
|
||||
*/
|
||||
public FakeMediaPeriod(
|
||||
TrackGroupArray trackGroupArray,
|
||||
long singleSampleTimeUs,
|
||||
EventDispatcher eventDispatcher,
|
||||
MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher,
|
||||
DrmSessionManager drmSessionManager,
|
||||
DrmSessionEventListener.EventDispatcher drmEventDispatcher,
|
||||
boolean deferOnPrepared) {
|
||||
this(
|
||||
trackGroupArray,
|
||||
TrackDataFactory.singleSampleWithTimeUs(singleSampleTimeUs),
|
||||
eventDispatcher,
|
||||
mediaSourceEventDispatcher,
|
||||
drmSessionManager,
|
||||
drmEventDispatcher,
|
||||
deferOnPrepared);
|
||||
}
|
||||
|
||||
|
|
@ -120,8 +129,9 @@ public class FakeMediaPeriod implements MediaPeriod {
|
|||
* @param trackGroupArray The track group array.
|
||||
* @param trackDataFactory A source for the underlying sample data for each track in {@code
|
||||
* trackGroupArray}.
|
||||
* @param eventDispatcher A dispatcher for media source events.
|
||||
* @param mediaSourceEventDispatcher A dispatcher for media source events.
|
||||
* @param drmSessionManager The DrmSessionManager used for DRM interactions.
|
||||
* @param drmEventDispatcher A dispatcher for {@link DrmSessionEventListener} events.
|
||||
* @param deferOnPrepared Whether {@link Callback#onPrepared(MediaPeriod)} should be called only
|
||||
* after {@link #setPreparationComplete()} has been called. If {@code false} preparation
|
||||
* completes immediately.
|
||||
|
|
@ -129,18 +139,20 @@ public class FakeMediaPeriod implements MediaPeriod {
|
|||
public FakeMediaPeriod(
|
||||
TrackGroupArray trackGroupArray,
|
||||
TrackDataFactory trackDataFactory,
|
||||
EventDispatcher eventDispatcher,
|
||||
MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher,
|
||||
DrmSessionManager drmSessionManager,
|
||||
DrmSessionEventListener.EventDispatcher drmEventDispatcher,
|
||||
boolean deferOnPrepared) {
|
||||
this.trackGroupArray = trackGroupArray;
|
||||
this.mediaSourceEventDispatcher = mediaSourceEventDispatcher;
|
||||
this.drmSessionManager = drmSessionManager;
|
||||
this.eventDispatcher = eventDispatcher;
|
||||
this.drmEventDispatcher = drmEventDispatcher;
|
||||
this.deferOnPrepared = deferOnPrepared;
|
||||
this.trackDataFactory = trackDataFactory;
|
||||
discontinuityPositionUs = C.TIME_UNSET;
|
||||
sampleStreams = new ArrayList<>();
|
||||
fakePreparationLoadTaskId = LoadEventInfo.getNewId();
|
||||
eventDispatcher.mediaPeriodCreated();
|
||||
mediaSourceEventDispatcher.mediaPeriodCreated();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -177,12 +189,12 @@ public class FakeMediaPeriod implements MediaPeriod {
|
|||
for (int i = 0; i < sampleStreams.size(); i++) {
|
||||
releaseSampleStream(sampleStreams.get(i));
|
||||
}
|
||||
eventDispatcher.mediaPeriodReleased();
|
||||
mediaSourceEventDispatcher.mediaPeriodReleased();
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void prepare(Callback callback, long positionUs) {
|
||||
eventDispatcher.loadStarted(
|
||||
mediaSourceEventDispatcher.loadStarted(
|
||||
new LoadEventInfo(fakePreparationLoadTaskId, FAKE_DATA_SPEC, SystemClock.elapsedRealtime()),
|
||||
C.DATA_TYPE_MEDIA,
|
||||
C.TRACK_TYPE_UNKNOWN,
|
||||
|
|
@ -232,7 +244,13 @@ public class FakeMediaPeriod implements MediaPeriod {
|
|||
int indexInTrackGroup = selection.getIndexInTrackGroup(selection.getSelectedIndex());
|
||||
assertThat(indexInTrackGroup).isAtLeast(0);
|
||||
assertThat(indexInTrackGroup).isLessThan(trackGroup.length);
|
||||
streams[i] = createSampleStream(positionUs, selection, drmSessionManager, eventDispatcher);
|
||||
streams[i] =
|
||||
createSampleStream(
|
||||
positionUs,
|
||||
selection,
|
||||
mediaSourceEventDispatcher,
|
||||
drmSessionManager,
|
||||
drmEventDispatcher);
|
||||
sampleStreams.add(streams[i]);
|
||||
streamResetFlags[i] = true;
|
||||
}
|
||||
|
|
@ -254,7 +272,7 @@ public class FakeMediaPeriod implements MediaPeriod {
|
|||
public long readDiscontinuity() {
|
||||
assertThat(prepared).isTrue();
|
||||
if (!notifiedReadingStarted) {
|
||||
eventDispatcher.readingStarted();
|
||||
mediaSourceEventDispatcher.readingStarted();
|
||||
notifiedReadingStarted = true;
|
||||
}
|
||||
long positionDiscontinuityUs = this.discontinuityPositionUs;
|
||||
|
|
@ -304,23 +322,28 @@ public class FakeMediaPeriod implements MediaPeriod {
|
|||
*
|
||||
* @param positionUs The position at which the tracks were selected, in microseconds.
|
||||
* @param selection A selection of tracks.
|
||||
* @param mediaSourceEventDispatcher A dispatcher for {@link MediaSourceEventListener} events that
|
||||
* should be used by the sample stream.
|
||||
* @param drmSessionManager The DRM session manager.
|
||||
* @param eventDispatcher A dispatcher for events that should be used by the sample stream.
|
||||
* @param drmEventDispatcher A dispatcher for {@link DrmSessionEventListener} events that should
|
||||
* be used by the sample stream.
|
||||
* @return A {@link SampleStream} for this selection.
|
||||
*/
|
||||
protected SampleStream createSampleStream(
|
||||
long positionUs,
|
||||
TrackSelection selection,
|
||||
MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher,
|
||||
DrmSessionManager drmSessionManager,
|
||||
EventDispatcher eventDispatcher) {
|
||||
DrmSessionEventListener.EventDispatcher drmEventDispatcher) {
|
||||
FakeSampleStream sampleStream =
|
||||
new FakeSampleStream(
|
||||
mediaSourceEventDispatcher,
|
||||
drmSessionManager,
|
||||
eventDispatcher,
|
||||
drmEventDispatcher,
|
||||
selection.getSelectedFormat(),
|
||||
trackDataFactory.create(
|
||||
selection.getSelectedFormat(),
|
||||
Assertions.checkNotNull(eventDispatcher.mediaPeriodId)));
|
||||
Assertions.checkNotNull(mediaSourceEventDispatcher.mediaPeriodId)));
|
||||
sampleStream.seekTo(positionUs);
|
||||
return sampleStream;
|
||||
}
|
||||
|
|
@ -329,7 +352,8 @@ public class FakeMediaPeriod implements MediaPeriod {
|
|||
* Seeks inside the given sample stream.
|
||||
*
|
||||
* @param sampleStream A sample stream that was created by a call to {@link
|
||||
* #createSampleStream(long, TrackSelection, DrmSessionManager, EventDispatcher)}.
|
||||
* #createSampleStream(long, TrackSelection, MediaSourceEventListener.EventDispatcher,
|
||||
* DrmSessionManager, DrmSessionEventListener.EventDispatcher)}.
|
||||
* @param positionUs The position to seek to, in microseconds.
|
||||
*/
|
||||
protected void seekSampleStream(SampleStream sampleStream, long positionUs) {
|
||||
|
|
@ -341,7 +365,8 @@ public class FakeMediaPeriod implements MediaPeriod {
|
|||
* Releases the given sample stream.
|
||||
*
|
||||
* @param sampleStream A sample stream that was created by a call to {@link
|
||||
* #createSampleStream(long, TrackSelection, DrmSessionManager, EventDispatcher)}.
|
||||
* #createSampleStream(long, TrackSelection, MediaSourceEventListener.EventDispatcher,
|
||||
* DrmSessionManager, DrmSessionEventListener.EventDispatcher)}.
|
||||
*/
|
||||
protected void releaseSampleStream(SampleStream sampleStream) {
|
||||
((FakeSampleStream) sampleStream).release();
|
||||
|
|
@ -350,7 +375,7 @@ public class FakeMediaPeriod implements MediaPeriod {
|
|||
private void finishPreparation() {
|
||||
prepared = true;
|
||||
Util.castNonNull(prepareCallback).onPrepared(this);
|
||||
eventDispatcher.loadCompleted(
|
||||
mediaSourceEventDispatcher.loadCompleted(
|
||||
new LoadEventInfo(
|
||||
fakePreparationLoadTaskId,
|
||||
FAKE_DATA_SPEC,
|
||||
|
|
@ -373,7 +398,8 @@ public class FakeMediaPeriod implements MediaPeriod {
|
|||
|
||||
/**
|
||||
* Returns the list of {@link FakeSampleStreamItem}s that will be passed to {@link
|
||||
* FakeSampleStream#FakeSampleStream(DrmSessionManager, EventDispatcher, Format, List)}.
|
||||
* FakeSampleStream#FakeSampleStream(MediaSourceEventListener.EventDispatcher,
|
||||
* DrmSessionManager, DrmSessionEventListener.EventDispatcher, Format, List)}.
|
||||
*
|
||||
* @param format The format of the track to provide data for.
|
||||
* @param mediaPeriodId The {@link MediaPeriodId} to provide data for.
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import com.google.android.exoplayer2.Format;
|
|||
import com.google.android.exoplayer2.MediaItem;
|
||||
import com.google.android.exoplayer2.Timeline;
|
||||
import com.google.android.exoplayer2.Timeline.Period;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionEventListener;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.source.BaseMediaSource;
|
||||
import com.google.android.exoplayer2.source.ForwardingTimeline;
|
||||
|
|
@ -33,7 +34,7 @@ import com.google.android.exoplayer2.source.LoadEventInfo;
|
|||
import com.google.android.exoplayer2.source.MediaLoadData;
|
||||
import com.google.android.exoplayer2.source.MediaPeriod;
|
||||
import com.google.android.exoplayer2.source.MediaSource;
|
||||
import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher;
|
||||
import com.google.android.exoplayer2.source.MediaSourceEventListener;
|
||||
import com.google.android.exoplayer2.source.TrackGroup;
|
||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||
import com.google.android.exoplayer2.testutil.FakeMediaPeriod.TrackDataFactory;
|
||||
|
|
@ -215,11 +216,19 @@ public class FakeMediaSource extends BaseMediaSource {
|
|||
int periodIndex = castNonNull(timeline).getIndexOfPeriod(id.periodUid);
|
||||
Assertions.checkArgument(periodIndex != C.INDEX_UNSET);
|
||||
Period period = timeline.getPeriod(periodIndex, new Period());
|
||||
EventDispatcher eventDispatcher =
|
||||
MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher =
|
||||
createEventDispatcher(period.windowIndex, id, period.getPositionInWindowMs());
|
||||
DrmSessionEventListener.EventDispatcher drmEventDispatcher =
|
||||
createDrmEventDispatcher(period.windowIndex, id);
|
||||
FakeMediaPeriod mediaPeriod =
|
||||
createFakeMediaPeriod(
|
||||
id, trackGroupArray, allocator, drmSessionManager, eventDispatcher, transferListener);
|
||||
id,
|
||||
trackGroupArray,
|
||||
allocator,
|
||||
mediaSourceEventDispatcher,
|
||||
drmSessionManager,
|
||||
drmEventDispatcher,
|
||||
transferListener);
|
||||
activeMediaPeriods.add(mediaPeriod);
|
||||
createdMediaPeriods.add(id);
|
||||
return mediaPeriod;
|
||||
|
|
@ -308,7 +317,10 @@ public class FakeMediaSource extends BaseMediaSource {
|
|||
* @param id The identifier of the period.
|
||||
* @param trackGroupArray The {@link TrackGroupArray} supported by the media period.
|
||||
* @param allocator An {@link Allocator} from which to obtain media buffer allocations.
|
||||
* @param eventDispatcher An {@link EventDispatcher} to dispatch media source events.
|
||||
* @param mediaSourceEventDispatcher An {@link MediaSourceEventListener.EventDispatcher} to
|
||||
* dispatch media source events.
|
||||
* @param drmEventDispatcher An {@link MediaSourceEventListener.EventDispatcher} to dispatch DRM
|
||||
* events.
|
||||
* @param transferListener The transfer listener which should be informed of any data transfers.
|
||||
* May be null if no listener is available.
|
||||
* @return A new {@link FakeMediaPeriod}.
|
||||
|
|
@ -318,8 +330,9 @@ public class FakeMediaSource extends BaseMediaSource {
|
|||
MediaPeriodId id,
|
||||
TrackGroupArray trackGroupArray,
|
||||
Allocator allocator,
|
||||
MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher,
|
||||
DrmSessionManager drmSessionManager,
|
||||
EventDispatcher eventDispatcher,
|
||||
DrmSessionEventListener.EventDispatcher drmEventDispatcher,
|
||||
@Nullable TransferListener transferListener) {
|
||||
long positionInWindowUs =
|
||||
timeline.getPeriodByUid(id.periodUid, new Period()).getPositionInWindowUs();
|
||||
|
|
@ -329,8 +342,9 @@ public class FakeMediaSource extends BaseMediaSource {
|
|||
trackDataFactory != null
|
||||
? trackDataFactory
|
||||
: TrackDataFactory.singleSampleWithTimeUs(defaultFirstSampleTimeUs),
|
||||
eventDispatcher,
|
||||
mediaSourceEventDispatcher,
|
||||
drmSessionManager,
|
||||
drmEventDispatcher,
|
||||
/* deferOnPrepared= */ false);
|
||||
}
|
||||
|
||||
|
|
@ -347,7 +361,8 @@ public class FakeMediaSource extends BaseMediaSource {
|
|||
/* mediaStartTimeMs= */ C.TIME_UNSET,
|
||||
/* mediaEndTimeMs = */ C.TIME_UNSET);
|
||||
long elapsedRealTimeMs = SystemClock.elapsedRealtime();
|
||||
EventDispatcher eventDispatcher = createEventDispatcher(/* mediaPeriodId= */ null);
|
||||
MediaSourceEventListener.EventDispatcher eventDispatcher =
|
||||
createEventDispatcher(/* mediaPeriodId= */ null);
|
||||
long loadTaskId = LoadEventInfo.getNewId();
|
||||
eventDispatcher.loadStarted(
|
||||
new LoadEventInfo(
|
||||
|
|
|
|||
|
|
@ -25,8 +25,9 @@ import com.google.android.exoplayer2.FormatHolder;
|
|||
import com.google.android.exoplayer2.decoder.DecoderInputBuffer;
|
||||
import com.google.android.exoplayer2.drm.DrmInitData;
|
||||
import com.google.android.exoplayer2.drm.DrmSession;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionEventListener;
|
||||
import com.google.android.exoplayer2.drm.DrmSessionManager;
|
||||
import com.google.android.exoplayer2.source.MediaSourceEventListener.EventDispatcher;
|
||||
import com.google.android.exoplayer2.source.MediaSourceEventListener;
|
||||
import com.google.android.exoplayer2.source.SampleStream;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
|
|
@ -126,10 +127,11 @@ public class FakeSampleStream implements SampleStream {
|
|||
}
|
||||
}
|
||||
|
||||
@Nullable private final MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher;
|
||||
private final Format initialFormat;
|
||||
private final List<FakeSampleStreamItem> fakeSampleStreamItems;
|
||||
private final DrmSessionManager drmSessionManager;
|
||||
@Nullable private final EventDispatcher eventDispatcher;
|
||||
private final DrmSessionEventListener.EventDispatcher drmEventDispatcher;
|
||||
|
||||
private int sampleItemIndex;
|
||||
private @MonotonicNonNull Format downstreamFormat;
|
||||
|
|
@ -140,8 +142,11 @@ public class FakeSampleStream implements SampleStream {
|
|||
* Creates a fake sample stream which outputs the given {@link Format} followed by the provided
|
||||
* {@link FakeSampleStreamItem items}.
|
||||
*
|
||||
* @param mediaSourceEventDispatcher A {@link MediaSourceEventListener.EventDispatcher} to notify
|
||||
* of media events.
|
||||
* @param drmSessionManager A {@link DrmSessionManager} for DRM interactions.
|
||||
* @param eventDispatcher An {@link EventDispatcher} to notify of read events.
|
||||
* @param drmEventDispatcher A {@link DrmSessionEventListener.EventDispatcher} to notify of DRM
|
||||
* events.
|
||||
* @param initialFormat The first {@link Format} to output.
|
||||
* @param fakeSampleStreamItems The {@link FakeSampleStreamItem items} to customize the return
|
||||
* values of {@link #readData(FormatHolder, DecoderInputBuffer, boolean)}. This is assumed to
|
||||
|
|
@ -150,12 +155,14 @@ public class FakeSampleStream implements SampleStream {
|
|||
* FakeSampleStreamItem#END_OF_STREAM_ITEM}.
|
||||
*/
|
||||
public FakeSampleStream(
|
||||
@Nullable MediaSourceEventListener.EventDispatcher mediaSourceEventDispatcher,
|
||||
DrmSessionManager drmSessionManager,
|
||||
@Nullable EventDispatcher eventDispatcher,
|
||||
DrmSessionEventListener.EventDispatcher drmEventDispatcher,
|
||||
Format initialFormat,
|
||||
List<FakeSampleStreamItem> fakeSampleStreamItems) {
|
||||
this.mediaSourceEventDispatcher = mediaSourceEventDispatcher;
|
||||
this.drmSessionManager = drmSessionManager;
|
||||
this.eventDispatcher = eventDispatcher;
|
||||
this.drmEventDispatcher = drmEventDispatcher;
|
||||
this.initialFormat = initialFormat;
|
||||
this.fakeSampleStreamItems = new ArrayList<>(fakeSampleStreamItems);
|
||||
}
|
||||
|
|
@ -268,13 +275,13 @@ public class FakeSampleStream implements SampleStream {
|
|||
Looper playbackLooper = Assertions.checkNotNull(Looper.myLooper());
|
||||
currentDrmSession =
|
||||
newDrmInitData != null
|
||||
? drmSessionManager.acquireSession(playbackLooper, eventDispatcher, newDrmInitData)
|
||||
? drmSessionManager.acquireSession(playbackLooper, drmEventDispatcher, newDrmInitData)
|
||||
: drmSessionManager.acquirePlaceholderSession(
|
||||
playbackLooper, MimeTypes.getTrackType(newFormat.sampleMimeType));
|
||||
outputFormatHolder.drmSession = currentDrmSession;
|
||||
|
||||
if (previousSession != null) {
|
||||
previousSession.release(eventDispatcher);
|
||||
previousSession.release(drmEventDispatcher);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -308,13 +315,13 @@ public class FakeSampleStream implements SampleStream {
|
|||
/** Release this SampleStream and all underlying resources. */
|
||||
public void release() {
|
||||
if (currentDrmSession != null) {
|
||||
currentDrmSession.release(eventDispatcher);
|
||||
currentDrmSession.release(drmEventDispatcher);
|
||||
currentDrmSession = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyEventDispatcher(Format format) {
|
||||
if (eventDispatcher != null) {
|
||||
if (mediaSourceEventDispatcher != null) {
|
||||
@Nullable SampleInfo sampleInfo = null;
|
||||
for (int i = sampleItemIndex; i < fakeSampleStreamItems.size(); i++) {
|
||||
sampleInfo = fakeSampleStreamItems.get(i).sampleInfo;
|
||||
|
|
@ -323,7 +330,7 @@ public class FakeSampleStream implements SampleStream {
|
|||
}
|
||||
}
|
||||
long nextSampleTimeUs = sampleInfo != null ? sampleInfo.timeUs : C.TIME_END_OF_SOURCE;
|
||||
eventDispatcher.downstreamFormatChanged(
|
||||
mediaSourceEventDispatcher.downstreamFormatChanged(
|
||||
C.TRACK_TYPE_UNKNOWN,
|
||||
format,
|
||||
C.SELECTION_REASON_UNKNOWN,
|
||||
|
|
|
|||
Loading…
Reference in a new issue