Remove deprecated debug listener methods from SimpleExoPlayer

- Once the ability to add debug listeners is removed, analyticsCollector
  is the only component that needs to receive the events. Hence it is
  called directly.
- It seemed less confusing to do the same thing for (non-debug) video and
  audio events, and to have AnalyticsCollector no longer implement
  VideoListener and AudioListener directly. This clears up confusion that
  arises as a result of the debug and non-debug interfaces defining the
  same methods in some cases, and having to be careful not to end up
  calling the corresponding AnalyticsCollector method twice.

PiperOrigin-RevId: 351835491
This commit is contained in:
olly 2021-01-14 19:05:00 +00:00 committed by Ian Baker
parent fa94fba2cb
commit 464f53373a
4 changed files with 117 additions and 177 deletions

View file

@ -69,6 +69,13 @@
`com.google.android.exoplayer2.video.VideoListener` instead.
* `SingleSampleMediaSource.EventListener` and constructors. Use
`MediaSourceEventListener` and `SingleSampleMediaSource.Factory`
* `SimpleExoPlayer.addVideoDebugListener`,
`SimpleExoPlayer.removeVideoDebugListener`,
`SimpleExoPlayer.addAudioDebugListener`
and `SimpleExoPlayer.removeAudioDebugListener`. Use
`SimpleExoPlayer.addAnalyticsListener` and
`SimpleExoPlayer.removeAnalyticsListener` instead.
* `AdaptiveMediaSourceEventListener`. Use `MediaSourceEventListener`
instead.
* Add a `LivePlaybackSpeedControl` component to control the playback speed
during live playbacks. This allows the player to stay close to the

View file

@ -15,6 +15,8 @@
*/
package com.google.android.exoplayer2.video;
import com.google.android.exoplayer2.C;
/** A listener for metadata corresponding to video being rendered. */
public interface VideoListener {
@ -41,12 +43,10 @@ public interface VideoListener {
* Called each time there's a change in the size of the surface onto which the video is being
* rendered.
*
* @param width The surface width in pixels. May be {@link
* com.google.android.exoplayer2.C#LENGTH_UNSET} if unknown, or 0 if the video is not rendered
* onto a surface.
* @param height The surface height in pixels. May be {@link
* com.google.android.exoplayer2.C#LENGTH_UNSET} if unknown, or 0 if the video is not rendered
* onto a surface.
* @param width The surface width in pixels. May be {@link C#LENGTH_UNSET} if unknown, or 0 if the
* video is not rendered onto a surface.
* @param height The surface height in pixels. May be {@link C#LENGTH_UNSET} if unknown, or 0 if
* the video is not rendered onto a surface.
*/
default void onSurfaceSizeChanged(int width, int height) {}

View file

@ -574,8 +574,6 @@ public class SimpleExoPlayer extends BasePlayer
private final CopyOnWriteArraySet<TextOutput> textOutputs;
private final CopyOnWriteArraySet<MetadataOutput> metadataOutputs;
private final CopyOnWriteArraySet<DeviceListener> deviceListeners;
private final CopyOnWriteArraySet<VideoRendererEventListener> videoDebugListeners;
private final CopyOnWriteArraySet<AudioRendererEventListener> audioDebugListeners;
private final AnalyticsCollector analyticsCollector;
private final AudioBecomingNoisyManager audioBecomingNoisyManager;
private final AudioFocusManager audioFocusManager;
@ -650,8 +648,6 @@ public class SimpleExoPlayer extends BasePlayer
textOutputs = new CopyOnWriteArraySet<>();
metadataOutputs = new CopyOnWriteArraySet<>();
deviceListeners = new CopyOnWriteArraySet<>();
videoDebugListeners = new CopyOnWriteArraySet<>();
audioDebugListeners = new CopyOnWriteArraySet<>();
Handler eventHandler = new Handler(builder.looper);
renderers =
builder.renderersFactory.createRenderers(
@ -689,11 +685,6 @@ public class SimpleExoPlayer extends BasePlayer
builder.looper,
/* wrappingPlayer= */ this);
player.addListener(componentListener);
videoDebugListeners.add(analyticsCollector);
videoListeners.add(analyticsCollector);
audioDebugListeners.add(analyticsCollector);
audioListeners.add(analyticsCollector);
addMetadataOutput(analyticsCollector);
audioBecomingNoisyManager =
new AudioBecomingNoisyManager(builder.context, eventHandler, componentListener);
@ -926,6 +917,7 @@ public class SimpleExoPlayer extends BasePlayer
this.audioAttributes = audioAttributes;
sendRendererMessage(C.TRACK_TYPE_AUDIO, Renderer.MSG_SET_AUDIO_ATTRIBUTES, audioAttributes);
streamVolumeManager.setStreamType(Util.getStreamTypeForAudioUsage(audioAttributes.usage));
analyticsCollector.onAudioAttributesChanged(audioAttributes);
for (AudioListener audioListener : audioListeners) {
audioListener.onAudioAttributesChanged(audioAttributes);
}
@ -964,6 +956,7 @@ public class SimpleExoPlayer extends BasePlayer
this.audioSessionId = audioSessionId;
sendRendererMessage(C.TRACK_TYPE_AUDIO, Renderer.MSG_SET_AUDIO_SESSION_ID, audioSessionId);
sendRendererMessage(C.TRACK_TYPE_VIDEO, Renderer.MSG_SET_AUDIO_SESSION_ID, audioSessionId);
analyticsCollector.onAudioSessionIdChanged(audioSessionId);
for (AudioListener audioListener : audioListeners) {
audioListener.onAudioSessionIdChanged(audioSessionId);
}
@ -994,6 +987,7 @@ public class SimpleExoPlayer extends BasePlayer
}
this.audioVolume = audioVolume;
sendVolumeToRenderers();
analyticsCollector.onVolumeChanged(audioVolume);
for (AudioListener audioListener : audioListeners) {
audioListener.onVolumeChanged(audioVolume);
}
@ -1196,44 +1190,6 @@ public class SimpleExoPlayer extends BasePlayer
metadataOutputs.remove(listener);
}
/**
* @deprecated Use {@link #addAnalyticsListener(AnalyticsListener)} to get more detailed debug
* information.
*/
@Deprecated
public void addVideoDebugListener(VideoRendererEventListener listener) {
Assertions.checkNotNull(listener);
videoDebugListeners.add(listener);
}
/**
* @deprecated Use {@link #addAnalyticsListener(AnalyticsListener)} and {@link
* #removeAnalyticsListener(AnalyticsListener)} to get more detailed debug information.
*/
@Deprecated
public void removeVideoDebugListener(VideoRendererEventListener listener) {
videoDebugListeners.remove(listener);
}
/**
* @deprecated Use {@link #addAnalyticsListener(AnalyticsListener)} to get more detailed debug
* information.
*/
@Deprecated
public void addAudioDebugListener(AudioRendererEventListener listener) {
Assertions.checkNotNull(listener);
audioDebugListeners.add(listener);
}
/**
* @deprecated Use {@link #addAnalyticsListener(AnalyticsListener)} and {@link
* #removeAnalyticsListener(AnalyticsListener)} to get more detailed debug information.
*/
@Deprecated
public void removeAudioDebugListener(AudioRendererEventListener listener) {
audioDebugListeners.remove(listener);
}
// ExoPlayer implementation
@Override
@ -1939,6 +1895,7 @@ public class SimpleExoPlayer extends BasePlayer
if (width != surfaceWidth || height != surfaceHeight) {
surfaceWidth = width;
surfaceHeight = height;
analyticsCollector.onSurfaceSizeChanged(width, height);
for (VideoListener videoListener : videoListeners) {
videoListener.onSurfaceSizeChanged(width, height);
}
@ -1952,14 +1909,8 @@ public class SimpleExoPlayer extends BasePlayer
@SuppressWarnings("SuspiciousMethodCalls")
private void notifySkipSilenceEnabledChanged() {
analyticsCollector.onSkipSilenceEnabledChanged(skipSilenceEnabled);
for (AudioListener listener : audioListeners) {
// Prevent duplicate notification if a listener is both a AudioRendererEventListener and
// a AudioListener, as they have the same method signature.
if (!audioDebugListeners.contains(listener)) {
listener.onSkipSilenceEnabledChanged(skipSilenceEnabled);
}
}
for (AudioRendererEventListener listener : audioDebugListeners) {
listener.onSkipSilenceEnabledChanged(skipSilenceEnabled);
}
}
@ -2082,86 +2033,64 @@ public class SimpleExoPlayer extends BasePlayer
@Override
public void onVideoEnabled(DecoderCounters counters) {
videoDecoderCounters = counters;
for (VideoRendererEventListener videoDebugListener : videoDebugListeners) {
videoDebugListener.onVideoEnabled(counters);
}
analyticsCollector.onVideoEnabled(counters);
}
@Override
public void onVideoDecoderInitialized(
String decoderName, long initializedTimestampMs, long initializationDurationMs) {
for (VideoRendererEventListener videoDebugListener : videoDebugListeners) {
videoDebugListener.onVideoDecoderInitialized(
decoderName, initializedTimestampMs, initializationDurationMs);
}
analyticsCollector.onVideoDecoderInitialized(
decoderName, initializedTimestampMs, initializationDurationMs);
}
@Override
public void onVideoInputFormatChanged(
Format format, @Nullable DecoderReuseEvaluation decoderReuseEvaluation) {
videoFormat = format;
for (VideoRendererEventListener videoDebugListener : videoDebugListeners) {
videoDebugListener.onVideoInputFormatChanged(format, decoderReuseEvaluation);
}
analyticsCollector.onVideoInputFormatChanged(format, decoderReuseEvaluation);
}
@Override
public void onDroppedFrames(int count, long elapsed) {
for (VideoRendererEventListener videoDebugListener : videoDebugListeners) {
videoDebugListener.onDroppedFrames(count, elapsed);
}
analyticsCollector.onDroppedFrames(count, elapsed);
}
@Override
public void onVideoSizeChanged(
int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) {
analyticsCollector.onVideoSizeChanged(
width, height, unappliedRotationDegrees, pixelWidthHeightRatio);
for (VideoListener videoListener : videoListeners) {
// Prevent duplicate notification if a listener is both a VideoRendererEventListener and
// a VideoListener, as they have the same method signature.
if (!videoDebugListeners.contains(videoListener)) {
videoListener.onVideoSizeChanged(
width, height, unappliedRotationDegrees, pixelWidthHeightRatio);
}
}
for (VideoRendererEventListener videoDebugListener : videoDebugListeners) {
videoDebugListener.onVideoSizeChanged(
videoListener.onVideoSizeChanged(
width, height, unappliedRotationDegrees, pixelWidthHeightRatio);
}
}
@Override
public void onRenderedFirstFrame(Surface surface) {
analyticsCollector.onRenderedFirstFrame(surface);
if (SimpleExoPlayer.this.surface == surface) {
for (VideoListener videoListener : videoListeners) {
videoListener.onRenderedFirstFrame();
}
}
for (VideoRendererEventListener videoDebugListener : videoDebugListeners) {
videoDebugListener.onRenderedFirstFrame(surface);
}
}
@Override
public void onVideoDecoderReleased(String decoderName) {
for (VideoRendererEventListener videoDebugListener : videoDebugListeners) {
videoDebugListener.onVideoDecoderReleased(decoderName);
}
analyticsCollector.onVideoDecoderReleased(decoderName);
}
@Override
public void onVideoDisabled(DecoderCounters counters) {
for (VideoRendererEventListener videoDebugListener : videoDebugListeners) {
videoDebugListener.onVideoDisabled(counters);
}
analyticsCollector.onVideoDisabled(counters);
videoFormat = null;
videoDecoderCounters = null;
}
@Override
public void onVideoFrameProcessingOffset(long totalProcessingOffsetUs, int frameCount) {
for (VideoRendererEventListener videoDebugListener : videoDebugListeners) {
videoDebugListener.onVideoFrameProcessingOffset(totalProcessingOffsetUs, frameCount);
}
analyticsCollector.onVideoFrameProcessingOffset(totalProcessingOffsetUs, frameCount);
}
// AudioRendererEventListener implementation
@ -2169,55 +2098,41 @@ public class SimpleExoPlayer extends BasePlayer
@Override
public void onAudioEnabled(DecoderCounters counters) {
audioDecoderCounters = counters;
for (AudioRendererEventListener audioDebugListener : audioDebugListeners) {
audioDebugListener.onAudioEnabled(counters);
}
analyticsCollector.onAudioEnabled(counters);
}
@Override
public void onAudioDecoderInitialized(
String decoderName, long initializedTimestampMs, long initializationDurationMs) {
for (AudioRendererEventListener audioDebugListener : audioDebugListeners) {
audioDebugListener.onAudioDecoderInitialized(
decoderName, initializedTimestampMs, initializationDurationMs);
}
analyticsCollector.onAudioDecoderInitialized(
decoderName, initializedTimestampMs, initializationDurationMs);
}
@Override
public void onAudioInputFormatChanged(
Format format, @Nullable DecoderReuseEvaluation decoderReuseEvaluation) {
audioFormat = format;
for (AudioRendererEventListener audioDebugListener : audioDebugListeners) {
audioDebugListener.onAudioInputFormatChanged(format, decoderReuseEvaluation);
}
analyticsCollector.onAudioInputFormatChanged(format, decoderReuseEvaluation);
}
@Override
public void onAudioPositionAdvancing(long playoutStartSystemTimeMs) {
for (AudioRendererEventListener audioDebugListener : audioDebugListeners) {
audioDebugListener.onAudioPositionAdvancing(playoutStartSystemTimeMs);
}
analyticsCollector.onAudioPositionAdvancing(playoutStartSystemTimeMs);
}
@Override
public void onAudioUnderrun(int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs) {
for (AudioRendererEventListener audioDebugListener : audioDebugListeners) {
audioDebugListener.onAudioUnderrun(bufferSize, bufferSizeMs, elapsedSinceLastFeedMs);
}
analyticsCollector.onAudioUnderrun(bufferSize, bufferSizeMs, elapsedSinceLastFeedMs);
}
@Override
public void onAudioDecoderReleased(String decoderName) {
for (AudioRendererEventListener audioDebugListener : audioDebugListeners) {
audioDebugListener.onAudioDecoderReleased(decoderName);
}
analyticsCollector.onAudioDecoderReleased(decoderName);
}
@Override
public void onAudioDisabled(DecoderCounters counters) {
for (AudioRendererEventListener audioDebugListener : audioDebugListeners) {
audioDebugListener.onAudioDisabled(counters);
}
analyticsCollector.onAudioDisabled(counters);
audioFormat = null;
audioDecoderCounters = null;
audioSessionId = C.AUDIO_SESSION_ID_UNSET;
@ -2232,6 +2147,11 @@ public class SimpleExoPlayer extends BasePlayer
notifySkipSilenceEnabledChanged();
}
@Override
public void onAudioSinkError(Exception audioSinkError) {
analyticsCollector.onAudioSinkError(audioSinkError);
}
// TextOutput implementation
@Override
@ -2246,6 +2166,7 @@ public class SimpleExoPlayer extends BasePlayer
@Override
public void onMetadata(Metadata metadata) {
analyticsCollector.onMetadata(metadata);
for (MetadataOutput metadataOutput : metadataOutputs) {
metadataOutput.onMetadata(metadata);
}

View file

@ -34,13 +34,11 @@ import com.google.android.exoplayer2.Timeline.Period;
import com.google.android.exoplayer2.Timeline.Window;
import com.google.android.exoplayer2.analytics.AnalyticsListener.EventTime;
import com.google.android.exoplayer2.audio.AudioAttributes;
import com.google.android.exoplayer2.audio.AudioListener;
import com.google.android.exoplayer2.audio.AudioRendererEventListener;
import com.google.android.exoplayer2.decoder.DecoderCounters;
import com.google.android.exoplayer2.decoder.DecoderReuseEvaluation;
import com.google.android.exoplayer2.drm.DrmSessionEventListener;
import com.google.android.exoplayer2.metadata.Metadata;
import com.google.android.exoplayer2.metadata.MetadataOutput;
import com.google.android.exoplayer2.source.LoadEventInfo;
import com.google.android.exoplayer2.source.MediaLoadData;
import com.google.android.exoplayer2.source.MediaSource.MediaPeriodId;
@ -52,7 +50,6 @@ import com.google.android.exoplayer2.util.Assertions;
import com.google.android.exoplayer2.util.Clock;
import com.google.android.exoplayer2.util.ListenerSet;
import com.google.android.exoplayer2.util.Util;
import com.google.android.exoplayer2.video.VideoListener;
import com.google.android.exoplayer2.video.VideoRendererEventListener;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableList;
@ -64,19 +61,15 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
/**
* Data collector which is able to forward analytics events to {@link AnalyticsListener}s by
* listening to all available ExoPlayer listeners.
* Data collector that forwards analytics events to {@link AnalyticsListener AnalyticsListeners}.
*/
public class AnalyticsCollector
implements Player.EventListener,
MetadataOutput,
AudioRendererEventListener,
VideoRendererEventListener,
MediaSourceEventListener,
BandwidthMeter.EventListener,
DrmSessionEventListener,
VideoListener,
AudioListener {
DrmSessionEventListener {
private final Clock clock;
private final Period period;
@ -196,9 +189,13 @@ public class AnalyticsCollector
// TODO: remove method.
}
// MetadataOutput implementation.
// MetadataOutput events.
@Override
/**
* Called when there is metadata associated with current playback time.
*
* @param metadata The metadata.
*/
public final void onMetadata(Metadata metadata) {
EventTime eventTime = generateCurrentPlayerMediaPeriodEventTime();
sendEvent(
@ -293,35 +290,6 @@ public class AnalyticsCollector
});
}
@Override
public final void onAudioSinkError(Exception audioSinkError) {
EventTime eventTime = generateReadingMediaPeriodEventTime();
sendEvent(
eventTime,
AnalyticsListener.EVENT_AUDIO_SINK_ERROR,
listener -> listener.onAudioSinkError(eventTime, audioSinkError));
}
// AudioListener implementation.
@Override
public final void onAudioSessionIdChanged(int audioSessionId) {
EventTime eventTime = generateReadingMediaPeriodEventTime();
sendEvent(
eventTime,
AnalyticsListener.EVENT_AUDIO_SESSION_ID,
listener -> listener.onAudioSessionIdChanged(eventTime, audioSessionId));
}
@Override
public final void onAudioAttributesChanged(AudioAttributes audioAttributes) {
EventTime eventTime = generateReadingMediaPeriodEventTime();
sendEvent(
eventTime,
AnalyticsListener.EVENT_AUDIO_ATTRIBUTES_CHANGED,
listener -> listener.onAudioAttributesChanged(eventTime, audioAttributes));
}
@Override
public final void onSkipSilenceEnabledChanged(boolean skipSilenceEnabled) {
EventTime eventTime = generateReadingMediaPeriodEventTime();
@ -332,12 +300,53 @@ public class AnalyticsCollector
}
@Override
public final void onVolumeChanged(float audioVolume) {
public final void onAudioSinkError(Exception audioSinkError) {
EventTime eventTime = generateReadingMediaPeriodEventTime();
sendEvent(
eventTime,
AnalyticsListener.EVENT_AUDIO_SINK_ERROR,
listener -> listener.onAudioSinkError(eventTime, audioSinkError));
}
// Additional audio events.
/**
* Called when the audio session ID changes.
*
* @param audioSessionId The audio session ID.
*/
public final void onAudioSessionIdChanged(int audioSessionId) {
EventTime eventTime = generateReadingMediaPeriodEventTime();
sendEvent(
eventTime,
AnalyticsListener.EVENT_AUDIO_SESSION_ID,
listener -> listener.onAudioSessionIdChanged(eventTime, audioSessionId));
}
/**
* Called when the audio attributes change.
*
* @param audioAttributes The audio attributes.
*/
public final void onAudioAttributesChanged(AudioAttributes audioAttributes) {
EventTime eventTime = generateReadingMediaPeriodEventTime();
sendEvent(
eventTime,
AnalyticsListener.EVENT_AUDIO_ATTRIBUTES_CHANGED,
listener -> listener.onAudioAttributesChanged(eventTime, audioAttributes));
}
/**
* Called when the volume changes.
*
* @param volume The new volume, with 0 being silence and 1 being unity gain.
*/
public final void onVolumeChanged(float volume) {
EventTime eventTime = generateReadingMediaPeriodEventTime();
sendEvent(
eventTime,
AnalyticsListener.EVENT_VOLUME_CHANGED,
listener -> listener.onVolumeChanged(eventTime, audioVolume));
listener -> listener.onVolumeChanged(eventTime, volume));
}
// VideoRendererEventListener implementation.
@ -415,6 +424,18 @@ public class AnalyticsCollector
});
}
@Override
public final void onVideoSizeChanged(
int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) {
EventTime eventTime = generateReadingMediaPeriodEventTime();
sendEvent(
eventTime,
AnalyticsListener.EVENT_VIDEO_SIZE_CHANGED,
listener ->
listener.onVideoSizeChanged(
eventTime, width, height, unappliedRotationDegrees, pixelWidthHeightRatio));
}
@Override
public final void onRenderedFirstFrame(@Nullable Surface surface) {
EventTime eventTime = generateReadingMediaPeriodEventTime();
@ -434,26 +455,17 @@ public class AnalyticsCollector
listener.onVideoFrameProcessingOffset(eventTime, totalProcessingOffsetUs, frameCount));
}
// VideoListener implementation.
// Additional video events.
@Override
public final void onRenderedFirstFrame() {
// Do nothing. Already reported in VideoRendererEventListener.onRenderedFirstFrame.
}
@Override
public final void onVideoSizeChanged(
int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) {
EventTime eventTime = generateReadingMediaPeriodEventTime();
sendEvent(
eventTime,
AnalyticsListener.EVENT_VIDEO_SIZE_CHANGED,
listener ->
listener.onVideoSizeChanged(
eventTime, width, height, unappliedRotationDegrees, pixelWidthHeightRatio));
}
@Override
/**
* Called each time there's a change in the size of the surface onto which the video is being
* rendered.
*
* @param width The surface width in pixels. May be {@link C#LENGTH_UNSET} if unknown, or 0 if the
* video is not rendered onto a surface.
* @param height The surface height in pixels. May be {@link C#LENGTH_UNSET} if unknown, or 0 if
* the video is not rendered onto a surface.
*/
public void onSurfaceSizeChanged(int width, int height) {
EventTime eventTime = generateReadingMediaPeriodEventTime();
sendEvent(