Add addListener/removeListener to BandwidthMeter.
That allows to add listeners after the BandwidthMeter has been created which is helpful as the BandwidthMeter instances are often long-lived static instances. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=204255299
This commit is contained in:
parent
9914587894
commit
78d7754f29
@ -24,7 +24,8 @@
|
||||
* Pass `BandwidthMeter` to `TrackSelection.Factory` which can be used to
|
||||
obtain bandwidth estimates in the future. Always null at the moment.
|
||||
* Add method to `BandwidthMeter` to return the `TransferListener` used to
|
||||
gather bandwidth information.
|
||||
gather bandwidth information. Also add methods to add and remove event
|
||||
listeners.
|
||||
* Pass `TransferListener` to `MediaSource`s to listen to media data transfers.
|
||||
Always null at the moment.
|
||||
* Add method to `DataSource` to add `TransferListener`s. Custom `DataSource`s
|
||||
|
@ -26,10 +26,10 @@ import android.support.annotation.Nullable;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.drm.DefaultDrmSessionEventListener.EventDispatcher;
|
||||
import com.google.android.exoplayer2.drm.DrmInitData.SchemeData;
|
||||
import com.google.android.exoplayer2.drm.ExoMediaDrm.KeyRequest;
|
||||
import com.google.android.exoplayer2.drm.ExoMediaDrm.ProvisionRequest;
|
||||
import com.google.android.exoplayer2.util.EventDispatcher;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
@ -81,7 +81,7 @@ import java.util.UUID;
|
||||
private final SchemeData schemeData;
|
||||
private final @DefaultDrmSessionManager.Mode int mode;
|
||||
private final HashMap<String, String> optionalKeyRequestParameters;
|
||||
private final EventDispatcher eventDispatcher;
|
||||
private final EventDispatcher<DefaultDrmSessionEventListener> eventDispatcher;
|
||||
private final int initialDrmRequestRetryCount;
|
||||
|
||||
/* package */ final MediaDrmCallback callback;
|
||||
@ -128,7 +128,7 @@ import java.util.UUID;
|
||||
HashMap<String, String> optionalKeyRequestParameters,
|
||||
MediaDrmCallback callback,
|
||||
Looper playbackLooper,
|
||||
EventDispatcher eventDispatcher,
|
||||
EventDispatcher<DefaultDrmSessionEventListener> eventDispatcher,
|
||||
int initialDrmRequestRetryCount) {
|
||||
this.uuid = uuid;
|
||||
this.provisioningManager = provisioningManager;
|
||||
@ -333,7 +333,7 @@ import java.util.UUID;
|
||||
onError(new KeysExpiredException());
|
||||
} else {
|
||||
state = STATE_OPENED_WITH_KEYS;
|
||||
eventDispatcher.drmKeysRestored();
|
||||
eventDispatcher.dispatch(DefaultDrmSessionEventListener::onDrmKeysRestored);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -414,7 +414,7 @@ import java.util.UUID;
|
||||
byte[] responseData = (byte[]) response;
|
||||
if (mode == DefaultDrmSessionManager.MODE_RELEASE) {
|
||||
mediaDrm.provideKeyResponse(offlineLicenseKeySetId, responseData);
|
||||
eventDispatcher.drmKeysRemoved();
|
||||
eventDispatcher.dispatch(DefaultDrmSessionEventListener::onDrmKeysRestored);
|
||||
} else {
|
||||
byte[] keySetId = mediaDrm.provideKeyResponse(sessionId, responseData);
|
||||
if ((mode == DefaultDrmSessionManager.MODE_DOWNLOAD
|
||||
@ -423,7 +423,7 @@ import java.util.UUID;
|
||||
offlineLicenseKeySetId = keySetId;
|
||||
}
|
||||
state = STATE_OPENED_WITH_KEYS;
|
||||
eventDispatcher.drmKeysLoaded();
|
||||
eventDispatcher.dispatch(DefaultDrmSessionEventListener::onDrmKeysLoaded);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
onKeysError(e);
|
||||
@ -447,7 +447,7 @@ import java.util.UUID;
|
||||
|
||||
private void onError(final Exception e) {
|
||||
lastException = new DrmSessionException(e);
|
||||
eventDispatcher.drmSessionManagerError(e);
|
||||
eventDispatcher.dispatch(listener -> listener.onDrmSessionManagerError(e));
|
||||
if (state != STATE_OPENED_WITH_KEYS) {
|
||||
state = STATE_ERROR;
|
||||
}
|
||||
|
@ -15,10 +15,7 @@
|
||||
*/
|
||||
package com.google.android.exoplayer2.drm;
|
||||
|
||||
import android.os.Handler;
|
||||
import com.google.android.exoplayer2.Player;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
/** Listener of {@link DefaultDrmSessionManager} events. */
|
||||
public interface DefaultDrmSessionEventListener {
|
||||
@ -45,97 +42,4 @@ public interface DefaultDrmSessionEventListener {
|
||||
|
||||
/** Called each time offline keys are removed. */
|
||||
void onDrmKeysRemoved();
|
||||
|
||||
/** Dispatches drm events to all registered listeners. */
|
||||
final class EventDispatcher {
|
||||
|
||||
private final CopyOnWriteArrayList<HandlerAndListener> listeners;
|
||||
|
||||
/** Creates event dispatcher. */
|
||||
public EventDispatcher() {
|
||||
listeners = new CopyOnWriteArrayList<>();
|
||||
}
|
||||
|
||||
/** Adds listener to event dispatcher. */
|
||||
public void addListener(Handler handler, DefaultDrmSessionEventListener eventListener) {
|
||||
Assertions.checkArgument(handler != null && eventListener != null);
|
||||
listeners.add(new HandlerAndListener(handler, eventListener));
|
||||
}
|
||||
|
||||
/** Removes listener from event dispatcher. */
|
||||
public void removeListener(DefaultDrmSessionEventListener eventListener) {
|
||||
for (HandlerAndListener handlerAndListener : listeners) {
|
||||
if (handlerAndListener.listener == eventListener) {
|
||||
listeners.remove(handlerAndListener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Dispatches {@link DefaultDrmSessionEventListener#onDrmKeysLoaded()}. */
|
||||
public void drmKeysLoaded() {
|
||||
for (HandlerAndListener handlerAndListener : listeners) {
|
||||
final DefaultDrmSessionEventListener listener = handlerAndListener.listener;
|
||||
handlerAndListener.handler.post(
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
listener.onDrmKeysLoaded();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/** Dispatches {@link DefaultDrmSessionEventListener#onDrmSessionManagerError(Exception)}. */
|
||||
public void drmSessionManagerError(final Exception e) {
|
||||
for (HandlerAndListener handlerAndListener : listeners) {
|
||||
final DefaultDrmSessionEventListener listener = handlerAndListener.listener;
|
||||
handlerAndListener.handler.post(
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
listener.onDrmSessionManagerError(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/** Dispatches {@link DefaultDrmSessionEventListener#onDrmKeysRestored()}. */
|
||||
public void drmKeysRestored() {
|
||||
for (HandlerAndListener handlerAndListener : listeners) {
|
||||
final DefaultDrmSessionEventListener listener = handlerAndListener.listener;
|
||||
handlerAndListener.handler.post(
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
listener.onDrmKeysRestored();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/** Dispatches {@link DefaultDrmSessionEventListener#onDrmKeysRemoved()}. */
|
||||
public void drmKeysRemoved() {
|
||||
for (HandlerAndListener handlerAndListener : listeners) {
|
||||
final DefaultDrmSessionEventListener listener = handlerAndListener.listener;
|
||||
handlerAndListener.handler.post(
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
listener.onDrmKeysRemoved();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static final class HandlerAndListener {
|
||||
|
||||
public final Handler handler;
|
||||
public final DefaultDrmSessionEventListener listener;
|
||||
|
||||
public HandlerAndListener(Handler handler, DefaultDrmSessionEventListener eventListener) {
|
||||
this.handler = handler;
|
||||
this.listener = eventListener;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,12 +26,12 @@ import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.drm.DefaultDrmSession.ProvisioningManager;
|
||||
import com.google.android.exoplayer2.drm.DefaultDrmSessionEventListener.EventDispatcher;
|
||||
import com.google.android.exoplayer2.drm.DrmInitData.SchemeData;
|
||||
import com.google.android.exoplayer2.drm.DrmSession.DrmSessionException;
|
||||
import com.google.android.exoplayer2.drm.ExoMediaDrm.OnEventListener;
|
||||
import com.google.android.exoplayer2.extractor.mp4.PsshAtomUtil;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.EventDispatcher;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
@ -93,7 +93,7 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
|
||||
private final ExoMediaDrm<T> mediaDrm;
|
||||
private final MediaDrmCallback callback;
|
||||
private final HashMap<String, String> optionalKeyRequestParameters;
|
||||
private final EventDispatcher eventDispatcher;
|
||||
private final EventDispatcher<DefaultDrmSessionEventListener> eventDispatcher;
|
||||
private final boolean multiSession;
|
||||
private final int initialDrmRequestRetryCount;
|
||||
|
||||
@ -354,7 +354,7 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
|
||||
this.mediaDrm = mediaDrm;
|
||||
this.callback = callback;
|
||||
this.optionalKeyRequestParameters = optionalKeyRequestParameters;
|
||||
this.eventDispatcher = new EventDispatcher();
|
||||
this.eventDispatcher = new EventDispatcher<>();
|
||||
this.multiSession = multiSession;
|
||||
this.initialDrmRequestRetryCount = initialDrmRequestRetryCount;
|
||||
mode = MODE_PLAYBACK;
|
||||
@ -512,7 +512,7 @@ public class DefaultDrmSessionManager<T extends ExoMediaCrypto> implements DrmSe
|
||||
schemeData = getSchemeData(drmInitData, uuid, false);
|
||||
if (schemeData == null) {
|
||||
final MissingSchemeDataException error = new MissingSchemeDataException(uuid);
|
||||
eventDispatcher.drmSessionManagerError(error);
|
||||
eventDispatcher.dispatch(listener -> listener.onDrmSessionManagerError(error));
|
||||
return new ErrorStateDrmSession<>(new DrmSessionException(error));
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.google.android.exoplayer2.upstream;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
/**
|
||||
@ -49,4 +50,19 @@ public interface BandwidthMeter {
|
||||
*/
|
||||
@Nullable
|
||||
TransferListener<? super DataSource> getTransferListener();
|
||||
|
||||
/**
|
||||
* Adds an {@link EventListener} to be informed of bandwidth samples.
|
||||
*
|
||||
* @param eventHandler A handler for events.
|
||||
* @param eventListener A listener of events.
|
||||
*/
|
||||
void addEventListener(Handler eventHandler, EventListener eventListener);
|
||||
|
||||
/**
|
||||
* Removes an {@link EventListener}.
|
||||
*
|
||||
* @param eventListener The listener to be removed.
|
||||
*/
|
||||
void removeEventListener(EventListener eventListener);
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ import android.os.Handler;
|
||||
import android.support.annotation.Nullable;
|
||||
import com.google.android.exoplayer2.util.Assertions;
|
||||
import com.google.android.exoplayer2.util.Clock;
|
||||
import com.google.android.exoplayer2.util.EventDispatcher;
|
||||
import com.google.android.exoplayer2.util.SlidingPercentile;
|
||||
|
||||
/**
|
||||
@ -105,16 +106,19 @@ public final class DefaultBandwidthMeter implements BandwidthMeter, TransferList
|
||||
* @return A bandwidth meter with the configured properties.
|
||||
*/
|
||||
public DefaultBandwidthMeter build() {
|
||||
return new DefaultBandwidthMeter(
|
||||
eventHandler, eventListener, initialBitrateEstimate, slidingWindowMaxWeight, clock);
|
||||
DefaultBandwidthMeter bandwidthMeter =
|
||||
new DefaultBandwidthMeter(initialBitrateEstimate, slidingWindowMaxWeight, clock);
|
||||
if (eventHandler != null && eventListener != null) {
|
||||
bandwidthMeter.addEventListener(eventHandler, eventListener);
|
||||
}
|
||||
return bandwidthMeter;
|
||||
}
|
||||
}
|
||||
|
||||
private static final int ELAPSED_MILLIS_FOR_ESTIMATE = 2000;
|
||||
private static final int BYTES_TRANSFERRED_FOR_ESTIMATE = 512 * 1024;
|
||||
|
||||
private final @Nullable Handler eventHandler;
|
||||
private final @Nullable EventListener eventListener;
|
||||
private final EventDispatcher<EventListener> eventDispatcher;
|
||||
private final SlidingPercentile slidingPercentile;
|
||||
private final Clock clock;
|
||||
|
||||
@ -128,39 +132,32 @@ public final class DefaultBandwidthMeter implements BandwidthMeter, TransferList
|
||||
|
||||
/** Creates a bandwidth meter with default parameters. */
|
||||
public DefaultBandwidthMeter() {
|
||||
this(
|
||||
/* eventHandler= */ null,
|
||||
/* eventListener= */ null,
|
||||
DEFAULT_INITIAL_BITRATE_ESTIMATE,
|
||||
DEFAULT_SLIDING_WINDOW_MAX_WEIGHT,
|
||||
Clock.DEFAULT);
|
||||
this(DEFAULT_INITIAL_BITRATE_ESTIMATE, DEFAULT_SLIDING_WINDOW_MAX_WEIGHT, Clock.DEFAULT);
|
||||
}
|
||||
|
||||
/** @deprecated Use {@link Builder} instead. */
|
||||
@Deprecated
|
||||
public DefaultBandwidthMeter(Handler eventHandler, EventListener eventListener) {
|
||||
this(
|
||||
eventHandler,
|
||||
eventListener,
|
||||
DEFAULT_INITIAL_BITRATE_ESTIMATE,
|
||||
DEFAULT_SLIDING_WINDOW_MAX_WEIGHT,
|
||||
Clock.DEFAULT);
|
||||
this(DEFAULT_INITIAL_BITRATE_ESTIMATE, DEFAULT_SLIDING_WINDOW_MAX_WEIGHT, Clock.DEFAULT);
|
||||
if (eventHandler != null && eventListener != null) {
|
||||
addEventListener(eventHandler, eventListener);
|
||||
}
|
||||
}
|
||||
|
||||
/** @deprecated Use {@link Builder} instead. */
|
||||
@Deprecated
|
||||
public DefaultBandwidthMeter(Handler eventHandler, EventListener eventListener, int maxWeight) {
|
||||
this(eventHandler, eventListener, DEFAULT_INITIAL_BITRATE_ESTIMATE, maxWeight, Clock.DEFAULT);
|
||||
this(DEFAULT_INITIAL_BITRATE_ESTIMATE, maxWeight, Clock.DEFAULT);
|
||||
if (eventHandler != null && eventListener != null) {
|
||||
addEventListener(eventHandler, eventListener);
|
||||
}
|
||||
}
|
||||
|
||||
private DefaultBandwidthMeter(
|
||||
@Nullable Handler eventHandler,
|
||||
@Nullable EventListener eventListener,
|
||||
long initialBitrateEstimate,
|
||||
int maxWeight,
|
||||
Clock clock) {
|
||||
this.eventHandler = eventHandler;
|
||||
this.eventListener = eventListener;
|
||||
this.eventDispatcher = new EventDispatcher<>();
|
||||
this.slidingPercentile = new SlidingPercentile(maxWeight);
|
||||
this.clock = clock;
|
||||
bitrateEstimate = initialBitrateEstimate;
|
||||
@ -176,6 +173,16 @@ public final class DefaultBandwidthMeter implements BandwidthMeter, TransferList
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEventListener(Handler eventHandler, EventListener eventListener) {
|
||||
eventDispatcher.addListener(eventHandler, eventListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeEventListener(EventListener eventListener) {
|
||||
eventDispatcher.removeListener(eventListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTransferInitializing(Object source, DataSpec dataSpec, boolean isNetwork) {
|
||||
// Do nothing.
|
||||
@ -219,17 +226,13 @@ public final class DefaultBandwidthMeter implements BandwidthMeter, TransferList
|
||||
bitrateEstimate = (long) slidingPercentile.getPercentile(0.5f);
|
||||
}
|
||||
}
|
||||
notifyBandwidthSample(sampleElapsedTimeMs, sampleBytesTransferred, bitrateEstimate);
|
||||
eventDispatcher.dispatch(
|
||||
listener ->
|
||||
listener.onBandwidthSample(
|
||||
sampleElapsedTimeMs, sampleBytesTransferred, bitrateEstimate));
|
||||
if (--streamCount > 0) {
|
||||
sampleStartTimeMs = nowMs;
|
||||
}
|
||||
sampleBytesTransferred = 0;
|
||||
}
|
||||
|
||||
private void notifyBandwidthSample(int elapsedMs, long bytes, long bitrate) {
|
||||
if (eventHandler != null && eventListener != null) {
|
||||
EventListener eventListener = this.eventListener;
|
||||
eventHandler.post(() -> eventListener.onBandwidthSample(elapsedMs, bytes, bitrate));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.android.exoplayer2.util;
|
||||
|
||||
import android.os.Handler;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
/**
|
||||
* Event dispatcher which allows listener registration.
|
||||
*
|
||||
* @param <T> The type of listener.
|
||||
*/
|
||||
public final class EventDispatcher<T> {
|
||||
|
||||
/** Functional interface to send an event. */
|
||||
public interface Event<T> {
|
||||
|
||||
/**
|
||||
* Sends the event to a listener.
|
||||
*
|
||||
* @param listener The listener to send the event to.
|
||||
*/
|
||||
void sendTo(T listener);
|
||||
}
|
||||
|
||||
/** The list of listeners and handlers. */
|
||||
private final CopyOnWriteArrayList<HandlerAndListener<T>> listeners;
|
||||
|
||||
/** Creates event dispatcher. */
|
||||
public EventDispatcher() {
|
||||
listeners = new CopyOnWriteArrayList<>();
|
||||
}
|
||||
|
||||
/** Adds listener to event dispatcher. */
|
||||
public void addListener(Handler handler, T eventListener) {
|
||||
Assertions.checkArgument(handler != null && eventListener != null);
|
||||
removeListener(eventListener);
|
||||
listeners.add(new HandlerAndListener<>(handler, eventListener));
|
||||
}
|
||||
|
||||
/** Removes listener from event dispatcher. */
|
||||
public void removeListener(T eventListener) {
|
||||
for (HandlerAndListener<T> handlerAndListener : listeners) {
|
||||
if (handlerAndListener.listener == eventListener) {
|
||||
listeners.remove(handlerAndListener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatches an event to all registered listeners.
|
||||
*
|
||||
* @param event The {@link Event}.
|
||||
*/
|
||||
public void dispatch(Event<T> event) {
|
||||
for (HandlerAndListener<T> handlerAndListener : listeners) {
|
||||
T eventListener = handlerAndListener.listener;
|
||||
handlerAndListener.handler.post(() -> event.sendTo(eventListener));
|
||||
}
|
||||
}
|
||||
|
||||
private static final class HandlerAndListener<T> {
|
||||
|
||||
public final Handler handler;
|
||||
public final T listener;
|
||||
|
||||
public HandlerAndListener(Handler handler, T eventListener) {
|
||||
this.handler = handler;
|
||||
this.listener = eventListener;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user