mirror of
https://github.com/samsonjs/media.git
synced 2026-03-27 09:45:47 +00:00
Use ListenerSet in AnalyticsCollector.
This ensures recursively sent events arrive in the correct order. Issue: #8048 PiperOrigin-RevId: 337812882
This commit is contained in:
parent
3c682610cf
commit
febf5d2031
3 changed files with 148 additions and 167 deletions
|
|
@ -22,6 +22,8 @@
|
|||
* Switch Guava dependency from `implementation` to `api`
|
||||
([#7905](https://github.com/google/ExoPlayer/issues/7905),
|
||||
([#7993](https://github.com/google/ExoPlayer/issues/7993)).
|
||||
* Fix bug where `AnalyticsListener` callbacks can arrive in the wrong
|
||||
order ([#8048](https://github.com/google/ExoPlayer/issues/8048)).
|
||||
* Track selection:
|
||||
* Add option to specify multiple preferred audio or text languages.
|
||||
* Data sources:
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
|
|||
import com.google.android.exoplayer2.upstream.BandwidthMeter;
|
||||
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.video.VideoListener;
|
||||
import com.google.android.exoplayer2.video.VideoRendererEventListener;
|
||||
import com.google.common.base.Objects;
|
||||
|
|
@ -54,7 +55,6 @@ import com.google.common.collect.ImmutableMap;
|
|||
import com.google.common.collect.Iterables;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArraySet;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
|
||||
|
||||
|
|
@ -73,7 +73,7 @@ public class AnalyticsCollector
|
|||
VideoListener,
|
||||
AudioListener {
|
||||
|
||||
private final CopyOnWriteArraySet<AnalyticsListener> listeners;
|
||||
private final ListenerSet<AnalyticsListener> listeners;
|
||||
private final Clock clock;
|
||||
private final Period period;
|
||||
private final Window window;
|
||||
|
|
@ -89,7 +89,7 @@ public class AnalyticsCollector
|
|||
*/
|
||||
public AnalyticsCollector(Clock clock) {
|
||||
this.clock = checkNotNull(clock);
|
||||
listeners = new CopyOnWriteArraySet<>();
|
||||
listeners = new ListenerSet<>();
|
||||
period = new Period();
|
||||
window = new Window();
|
||||
mediaPeriodQueueTracker = new MediaPeriodQueueTracker(period);
|
||||
|
|
@ -150,9 +150,7 @@ public class AnalyticsCollector
|
|||
if (!isSeeking) {
|
||||
EventTime eventTime = generateCurrentPlayerMediaPeriodEventTime();
|
||||
isSeeking = true;
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onSeekStarted(eventTime);
|
||||
}
|
||||
listeners.sendEvent(listener -> listener.onSeekStarted(eventTime));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -166,9 +164,7 @@ public class AnalyticsCollector
|
|||
@Override
|
||||
public final void onMetadata(Metadata metadata) {
|
||||
EventTime eventTime = generateCurrentPlayerMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onMetadata(eventTime, metadata);
|
||||
}
|
||||
listeners.sendEvent(listener -> listener.onMetadata(eventTime, metadata));
|
||||
}
|
||||
|
||||
// AudioRendererEventListener implementation.
|
||||
|
|
@ -177,10 +173,11 @@ public class AnalyticsCollector
|
|||
@Override
|
||||
public final void onAudioEnabled(DecoderCounters counters) {
|
||||
EventTime eventTime = generateReadingMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onAudioEnabled(eventTime, counters);
|
||||
listener.onDecoderEnabled(eventTime, C.TRACK_TYPE_AUDIO, counters);
|
||||
}
|
||||
listeners.sendEvent(
|
||||
listener -> {
|
||||
listener.onAudioEnabled(eventTime, counters);
|
||||
listener.onDecoderEnabled(eventTime, C.TRACK_TYPE_AUDIO, counters);
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
|
|
@ -188,48 +185,50 @@ public class AnalyticsCollector
|
|||
public final void onAudioDecoderInitialized(
|
||||
String decoderName, long initializedTimestampMs, long initializationDurationMs) {
|
||||
EventTime eventTime = generateReadingMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onAudioDecoderInitialized(eventTime, decoderName, initializationDurationMs);
|
||||
listener.onDecoderInitialized(
|
||||
eventTime, C.TRACK_TYPE_AUDIO, decoderName, initializationDurationMs);
|
||||
}
|
||||
listeners.sendEvent(
|
||||
listener -> {
|
||||
listener.onAudioDecoderInitialized(eventTime, decoderName, initializationDurationMs);
|
||||
listener.onDecoderInitialized(
|
||||
eventTime, C.TRACK_TYPE_AUDIO, decoderName, initializationDurationMs);
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public final void onAudioInputFormatChanged(Format format) {
|
||||
EventTime eventTime = generateReadingMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onAudioInputFormatChanged(eventTime, format);
|
||||
listener.onDecoderInputFormatChanged(eventTime, C.TRACK_TYPE_AUDIO, format);
|
||||
}
|
||||
listeners.sendEvent(
|
||||
listener -> {
|
||||
listener.onAudioInputFormatChanged(eventTime, format);
|
||||
listener.onDecoderInputFormatChanged(eventTime, C.TRACK_TYPE_AUDIO, format);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onAudioPositionAdvancing(long playoutStartSystemTimeMs) {
|
||||
EventTime eventTime = generateReadingMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onAudioPositionAdvancing(eventTime, playoutStartSystemTimeMs);
|
||||
}
|
||||
listeners.sendEvent(
|
||||
listener -> listener.onAudioPositionAdvancing(eventTime, playoutStartSystemTimeMs));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onAudioUnderrun(
|
||||
int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs) {
|
||||
EventTime eventTime = generateReadingMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onAudioUnderrun(eventTime, bufferSize, bufferSizeMs, elapsedSinceLastFeedMs);
|
||||
}
|
||||
listeners.sendEvent(
|
||||
listener ->
|
||||
listener.onAudioUnderrun(eventTime, bufferSize, bufferSizeMs, elapsedSinceLastFeedMs));
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public final void onAudioDisabled(DecoderCounters counters) {
|
||||
EventTime eventTime = generatePlayingMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onAudioDisabled(eventTime, counters);
|
||||
listener.onDecoderDisabled(eventTime, C.TRACK_TYPE_AUDIO, counters);
|
||||
}
|
||||
listeners.sendEvent(
|
||||
listener -> {
|
||||
listener.onAudioDisabled(eventTime, counters);
|
||||
listener.onDecoderDisabled(eventTime, C.TRACK_TYPE_AUDIO, counters);
|
||||
});
|
||||
}
|
||||
|
||||
// AudioListener implementation.
|
||||
|
|
@ -237,41 +236,32 @@ public class AnalyticsCollector
|
|||
@Override
|
||||
public final void onAudioSessionId(int audioSessionId) {
|
||||
EventTime eventTime = generateReadingMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onAudioSessionId(eventTime, audioSessionId);
|
||||
}
|
||||
listeners.sendEvent(listener -> listener.onAudioSessionId(eventTime, audioSessionId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAudioAttributesChanged(AudioAttributes audioAttributes) {
|
||||
EventTime eventTime = generateReadingMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onAudioAttributesChanged(eventTime, audioAttributes);
|
||||
}
|
||||
listeners.sendEvent(listener -> listener.onAudioAttributesChanged(eventTime, audioAttributes));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSkipSilenceEnabledChanged(boolean skipSilenceEnabled) {
|
||||
EventTime eventTime = generateReadingMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onSkipSilenceEnabledChanged(eventTime, skipSilenceEnabled);
|
||||
}
|
||||
listeners.sendEvent(
|
||||
listener -> listener.onSkipSilenceEnabledChanged(eventTime, skipSilenceEnabled));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAudioSinkError(Exception audioSinkError) {
|
||||
EventTime eventTime = generateReadingMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onAudioSinkError(eventTime, audioSinkError);
|
||||
}
|
||||
listeners.sendEvent(listener -> listener.onAudioSinkError(eventTime, audioSinkError));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onVolumeChanged(float audioVolume) {
|
||||
EventTime eventTime = generateReadingMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onVolumeChanged(eventTime, audioVolume);
|
||||
}
|
||||
listeners.sendEvent(listener -> listener.onVolumeChanged(eventTime, audioVolume));
|
||||
}
|
||||
|
||||
// VideoRendererEventListener implementation.
|
||||
|
|
@ -280,10 +270,11 @@ public class AnalyticsCollector
|
|||
@Override
|
||||
public final void onVideoEnabled(DecoderCounters counters) {
|
||||
EventTime eventTime = generateReadingMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onVideoEnabled(eventTime, counters);
|
||||
listener.onDecoderEnabled(eventTime, C.TRACK_TYPE_VIDEO, counters);
|
||||
}
|
||||
listeners.sendEvent(
|
||||
listener -> {
|
||||
listener.onVideoEnabled(eventTime, counters);
|
||||
listener.onDecoderEnabled(eventTime, C.TRACK_TYPE_VIDEO, counters);
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
|
|
@ -291,55 +282,54 @@ public class AnalyticsCollector
|
|||
public final void onVideoDecoderInitialized(
|
||||
String decoderName, long initializedTimestampMs, long initializationDurationMs) {
|
||||
EventTime eventTime = generateReadingMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onVideoDecoderInitialized(eventTime, decoderName, initializationDurationMs);
|
||||
listener.onDecoderInitialized(
|
||||
eventTime, C.TRACK_TYPE_VIDEO, decoderName, initializationDurationMs);
|
||||
}
|
||||
listeners.sendEvent(
|
||||
listener -> {
|
||||
listener.onVideoDecoderInitialized(eventTime, decoderName, initializationDurationMs);
|
||||
listener.onDecoderInitialized(
|
||||
eventTime, C.TRACK_TYPE_VIDEO, decoderName, initializationDurationMs);
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public final void onVideoInputFormatChanged(Format format) {
|
||||
EventTime eventTime = generateReadingMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onVideoInputFormatChanged(eventTime, format);
|
||||
listener.onDecoderInputFormatChanged(eventTime, C.TRACK_TYPE_VIDEO, format);
|
||||
}
|
||||
listeners.sendEvent(
|
||||
listener -> {
|
||||
listener.onVideoInputFormatChanged(eventTime, format);
|
||||
listener.onDecoderInputFormatChanged(eventTime, C.TRACK_TYPE_VIDEO, format);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onDroppedFrames(int count, long elapsedMs) {
|
||||
EventTime eventTime = generatePlayingMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onDroppedVideoFrames(eventTime, count, elapsedMs);
|
||||
}
|
||||
listeners.sendEvent(listener -> listener.onDroppedVideoFrames(eventTime, count, elapsedMs));
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public final void onVideoDisabled(DecoderCounters counters) {
|
||||
EventTime eventTime = generatePlayingMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onVideoDisabled(eventTime, counters);
|
||||
listener.onDecoderDisabled(eventTime, C.TRACK_TYPE_VIDEO, counters);
|
||||
}
|
||||
listeners.sendEvent(
|
||||
listener -> {
|
||||
listener.onVideoDisabled(eventTime, counters);
|
||||
listener.onDecoderDisabled(eventTime, C.TRACK_TYPE_VIDEO, counters);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onRenderedFirstFrame(@Nullable Surface surface) {
|
||||
EventTime eventTime = generateReadingMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onRenderedFirstFrame(eventTime, surface);
|
||||
}
|
||||
listeners.sendEvent(listener -> listener.onRenderedFirstFrame(eventTime, surface));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onVideoFrameProcessingOffset(long totalProcessingOffsetUs, int frameCount) {
|
||||
EventTime eventTime = generatePlayingMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onVideoFrameProcessingOffset(eventTime, totalProcessingOffsetUs, frameCount);
|
||||
}
|
||||
listeners.sendEvent(
|
||||
listener ->
|
||||
listener.onVideoFrameProcessingOffset(eventTime, totalProcessingOffsetUs, frameCount));
|
||||
}
|
||||
|
||||
// VideoListener implementation.
|
||||
|
|
@ -353,18 +343,16 @@ public class AnalyticsCollector
|
|||
public final void onVideoSizeChanged(
|
||||
int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio) {
|
||||
EventTime eventTime = generateReadingMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onVideoSizeChanged(
|
||||
eventTime, width, height, unappliedRotationDegrees, pixelWidthHeightRatio);
|
||||
}
|
||||
listeners.sendEvent(
|
||||
listener ->
|
||||
listener.onVideoSizeChanged(
|
||||
eventTime, width, height, unappliedRotationDegrees, pixelWidthHeightRatio));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSurfaceSizeChanged(int width, int height) {
|
||||
EventTime eventTime = generateReadingMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onSurfaceSizeChanged(eventTime, width, height);
|
||||
}
|
||||
listeners.sendEvent(listener -> listener.onSurfaceSizeChanged(eventTime, width, height));
|
||||
}
|
||||
|
||||
// MediaSourceEventListener implementation.
|
||||
|
|
@ -376,9 +364,8 @@ public class AnalyticsCollector
|
|||
LoadEventInfo loadEventInfo,
|
||||
MediaLoadData mediaLoadData) {
|
||||
EventTime eventTime = generateMediaPeriodEventTime(windowIndex, mediaPeriodId);
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onLoadStarted(eventTime, loadEventInfo, mediaLoadData);
|
||||
}
|
||||
listeners.sendEvent(
|
||||
listener -> listener.onLoadStarted(eventTime, loadEventInfo, mediaLoadData));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -388,9 +375,8 @@ public class AnalyticsCollector
|
|||
LoadEventInfo loadEventInfo,
|
||||
MediaLoadData mediaLoadData) {
|
||||
EventTime eventTime = generateMediaPeriodEventTime(windowIndex, mediaPeriodId);
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onLoadCompleted(eventTime, loadEventInfo, mediaLoadData);
|
||||
}
|
||||
listeners.sendEvent(
|
||||
listener -> listener.onLoadCompleted(eventTime, loadEventInfo, mediaLoadData));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -400,9 +386,8 @@ public class AnalyticsCollector
|
|||
LoadEventInfo loadEventInfo,
|
||||
MediaLoadData mediaLoadData) {
|
||||
EventTime eventTime = generateMediaPeriodEventTime(windowIndex, mediaPeriodId);
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onLoadCanceled(eventTime, loadEventInfo, mediaLoadData);
|
||||
}
|
||||
listeners.sendEvent(
|
||||
listener -> listener.onLoadCanceled(eventTime, loadEventInfo, mediaLoadData));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -414,27 +399,23 @@ public class AnalyticsCollector
|
|||
IOException error,
|
||||
boolean wasCanceled) {
|
||||
EventTime eventTime = generateMediaPeriodEventTime(windowIndex, mediaPeriodId);
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onLoadError(eventTime, loadEventInfo, mediaLoadData, error, wasCanceled);
|
||||
}
|
||||
listeners.sendEvent(
|
||||
listener ->
|
||||
listener.onLoadError(eventTime, loadEventInfo, mediaLoadData, error, wasCanceled));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onUpstreamDiscarded(
|
||||
int windowIndex, @Nullable MediaPeriodId mediaPeriodId, MediaLoadData mediaLoadData) {
|
||||
EventTime eventTime = generateMediaPeriodEventTime(windowIndex, mediaPeriodId);
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onUpstreamDiscarded(eventTime, mediaLoadData);
|
||||
}
|
||||
listeners.sendEvent(listener -> listener.onUpstreamDiscarded(eventTime, mediaLoadData));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onDownstreamFormatChanged(
|
||||
int windowIndex, @Nullable MediaPeriodId mediaPeriodId, MediaLoadData mediaLoadData) {
|
||||
EventTime eventTime = generateMediaPeriodEventTime(windowIndex, mediaPeriodId);
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onDownstreamFormatChanged(eventTime, mediaLoadData);
|
||||
}
|
||||
listeners.sendEvent(listener -> listener.onDownstreamFormatChanged(eventTime, mediaLoadData));
|
||||
}
|
||||
|
||||
// Player.EventListener implementation.
|
||||
|
|
@ -447,102 +428,83 @@ public class AnalyticsCollector
|
|||
public final void onTimelineChanged(Timeline timeline, @Player.TimelineChangeReason int reason) {
|
||||
mediaPeriodQueueTracker.onTimelineChanged(checkNotNull(player));
|
||||
EventTime eventTime = generateCurrentPlayerMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onTimelineChanged(eventTime, reason);
|
||||
}
|
||||
listeners.sendEvent(listener -> listener.onTimelineChanged(eventTime, reason));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onMediaItemTransition(
|
||||
@Nullable MediaItem mediaItem, @Player.MediaItemTransitionReason int reason) {
|
||||
EventTime eventTime = generateCurrentPlayerMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onMediaItemTransition(eventTime, mediaItem, reason);
|
||||
}
|
||||
listeners.sendEvent(listener -> listener.onMediaItemTransition(eventTime, mediaItem, reason));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onTracksChanged(
|
||||
TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
|
||||
EventTime eventTime = generateCurrentPlayerMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onTracksChanged(eventTime, trackGroups, trackSelections);
|
||||
}
|
||||
listeners.sendEvent(
|
||||
listener -> listener.onTracksChanged(eventTime, trackGroups, trackSelections));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onStaticMetadataChanged(List<Metadata> metadataList) {
|
||||
EventTime eventTime = generateCurrentPlayerMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onStaticMetadataChanged(eventTime, metadataList);
|
||||
}
|
||||
listeners.sendEvent(listener -> listener.onStaticMetadataChanged(eventTime, metadataList));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onIsLoadingChanged(boolean isLoading) {
|
||||
EventTime eventTime = generateCurrentPlayerMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onIsLoadingChanged(eventTime, isLoading);
|
||||
}
|
||||
listeners.sendEvent(listener -> listener.onIsLoadingChanged(eventTime, isLoading));
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public final void onPlayerStateChanged(boolean playWhenReady, @Player.State int playbackState) {
|
||||
EventTime eventTime = generateCurrentPlayerMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onPlayerStateChanged(eventTime, playWhenReady, playbackState);
|
||||
}
|
||||
listeners.sendEvent(
|
||||
listener -> listener.onPlayerStateChanged(eventTime, playWhenReady, playbackState));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onPlaybackStateChanged(@Player.State int state) {
|
||||
EventTime eventTime = generateCurrentPlayerMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onPlaybackStateChanged(eventTime, state);
|
||||
}
|
||||
listeners.sendEvent(listener -> listener.onPlaybackStateChanged(eventTime, state));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onPlayWhenReadyChanged(
|
||||
boolean playWhenReady, @Player.PlayWhenReadyChangeReason int reason) {
|
||||
EventTime eventTime = generateCurrentPlayerMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onPlayWhenReadyChanged(eventTime, playWhenReady, reason);
|
||||
}
|
||||
listeners.sendEvent(
|
||||
listener -> listener.onPlayWhenReadyChanged(eventTime, playWhenReady, reason));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlaybackSuppressionReasonChanged(
|
||||
@PlaybackSuppressionReason int playbackSuppressionReason) {
|
||||
EventTime eventTime = generateCurrentPlayerMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onPlaybackSuppressionReasonChanged(eventTime, playbackSuppressionReason);
|
||||
}
|
||||
listeners.sendEvent(
|
||||
listener ->
|
||||
listener.onPlaybackSuppressionReasonChanged(eventTime, playbackSuppressionReason));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onIsPlayingChanged(boolean isPlaying) {
|
||||
EventTime eventTime = generateCurrentPlayerMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onIsPlayingChanged(eventTime, isPlaying);
|
||||
}
|
||||
listeners.sendEvent(listener -> listener.onIsPlayingChanged(eventTime, isPlaying));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onRepeatModeChanged(@Player.RepeatMode int repeatMode) {
|
||||
EventTime eventTime = generateCurrentPlayerMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onRepeatModeChanged(eventTime, repeatMode);
|
||||
}
|
||||
listeners.sendEvent(listener -> listener.onRepeatModeChanged(eventTime, repeatMode));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onShuffleModeEnabledChanged(boolean shuffleModeEnabled) {
|
||||
EventTime eventTime = generateCurrentPlayerMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onShuffleModeChanged(eventTime, shuffleModeEnabled);
|
||||
}
|
||||
listeners.sendEvent(listener -> listener.onShuffleModeChanged(eventTime, shuffleModeEnabled));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -551,9 +513,7 @@ public class AnalyticsCollector
|
|||
error.mediaPeriodId != null
|
||||
? generateEventTime(error.mediaPeriodId)
|
||||
: generateCurrentPlayerMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onPlayerError(eventTime, error);
|
||||
}
|
||||
listeners.sendEvent(listener -> listener.onPlayerError(eventTime, error));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -563,26 +523,21 @@ public class AnalyticsCollector
|
|||
}
|
||||
mediaPeriodQueueTracker.onPositionDiscontinuity(checkNotNull(player));
|
||||
EventTime eventTime = generateCurrentPlayerMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onPositionDiscontinuity(eventTime, reason);
|
||||
}
|
||||
listeners.sendEvent(listener -> listener.onPositionDiscontinuity(eventTime, reason));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onPlaybackParametersChanged(PlaybackParameters playbackParameters) {
|
||||
EventTime eventTime = generateCurrentPlayerMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onPlaybackParametersChanged(eventTime, playbackParameters);
|
||||
}
|
||||
listeners.sendEvent(
|
||||
listener -> listener.onPlaybackParametersChanged(eventTime, playbackParameters));
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public final void onSeekProcessed() {
|
||||
EventTime eventTime = generateCurrentPlayerMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onSeekProcessed(eventTime);
|
||||
}
|
||||
listeners.sendEvent(listener -> listener.onSeekProcessed(eventTime));
|
||||
}
|
||||
|
||||
// BandwidthMeter.Listener implementation.
|
||||
|
|
@ -590,9 +545,8 @@ public class AnalyticsCollector
|
|||
@Override
|
||||
public final void onBandwidthSample(int elapsedMs, long bytes, long bitrate) {
|
||||
EventTime eventTime = generateLoadingMediaPeriodEventTime();
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onBandwidthEstimate(eventTime, elapsedMs, bytes, bitrate);
|
||||
}
|
||||
listeners.sendEvent(
|
||||
listener -> listener.onBandwidthEstimate(eventTime, elapsedMs, bytes, bitrate));
|
||||
}
|
||||
|
||||
// DefaultDrmSessionManager.EventListener implementation.
|
||||
|
|
@ -600,50 +554,38 @@ public class AnalyticsCollector
|
|||
@Override
|
||||
public final void onDrmSessionAcquired(int windowIndex, @Nullable MediaPeriodId mediaPeriodId) {
|
||||
EventTime eventTime = generateMediaPeriodEventTime(windowIndex, mediaPeriodId);
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onDrmSessionAcquired(eventTime);
|
||||
}
|
||||
listeners.sendEvent(listener -> listener.onDrmSessionAcquired(eventTime));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onDrmKeysLoaded(int windowIndex, @Nullable MediaPeriodId mediaPeriodId) {
|
||||
EventTime eventTime = generateMediaPeriodEventTime(windowIndex, mediaPeriodId);
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onDrmKeysLoaded(eventTime);
|
||||
}
|
||||
listeners.sendEvent(listener -> listener.onDrmKeysLoaded(eventTime));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onDrmSessionManagerError(
|
||||
int windowIndex, @Nullable MediaPeriodId mediaPeriodId, Exception error) {
|
||||
EventTime eventTime = generateMediaPeriodEventTime(windowIndex, mediaPeriodId);
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onDrmSessionManagerError(eventTime, error);
|
||||
}
|
||||
listeners.sendEvent(listener -> listener.onDrmSessionManagerError(eventTime, error));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onDrmKeysRestored(int windowIndex, @Nullable MediaPeriodId mediaPeriodId) {
|
||||
EventTime eventTime = generateMediaPeriodEventTime(windowIndex, mediaPeriodId);
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onDrmKeysRestored(eventTime);
|
||||
}
|
||||
listeners.sendEvent(listener -> listener.onDrmKeysRestored(eventTime));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onDrmKeysRemoved(int windowIndex, @Nullable MediaPeriodId mediaPeriodId) {
|
||||
EventTime eventTime = generateMediaPeriodEventTime(windowIndex, mediaPeriodId);
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onDrmKeysRemoved(eventTime);
|
||||
}
|
||||
listeners.sendEvent(listener -> listener.onDrmKeysRemoved(eventTime));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onDrmSessionReleased(int windowIndex, @Nullable MediaPeriodId mediaPeriodId) {
|
||||
EventTime eventTime = generateMediaPeriodEventTime(windowIndex, mediaPeriodId);
|
||||
for (AnalyticsListener listener : listeners) {
|
||||
listener.onDrmSessionReleased(eventTime);
|
||||
}
|
||||
listeners.sendEvent(listener -> listener.onDrmSessionReleased(eventTime));
|
||||
}
|
||||
|
||||
// Internal methods.
|
||||
|
|
|
|||
|
|
@ -18,6 +18,10 @@ package com.google.android.exoplayer2.analytics;
|
|||
import static com.google.android.exoplayer2.testutil.FakeSampleStream.FakeSampleStreamItem.END_OF_STREAM_ITEM;
|
||||
import static com.google.android.exoplayer2.testutil.FakeSampleStream.FakeSampleStreamItem.oneByteSample;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.spy;
|
||||
|
||||
import android.view.Surface;
|
||||
import androidx.annotation.Nullable;
|
||||
|
|
@ -60,6 +64,7 @@ import com.google.android.exoplayer2.testutil.FakeTimeline.TimelineWindowDefinit
|
|||
import com.google.android.exoplayer2.testutil.FakeVideoRenderer;
|
||||
import com.google.android.exoplayer2.testutil.TestUtil;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
|
||||
import com.google.android.exoplayer2.util.Clock;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import java.io.IOException;
|
||||
|
|
@ -71,6 +76,8 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InOrder;
|
||||
import org.mockito.Mockito;
|
||||
|
||||
/** Integration test for {@link AnalyticsCollector}. */
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
|
|
@ -1646,6 +1653,36 @@ public final class AnalyticsCollectorTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void recursiveListenerInvocation_arrivesInCorrectOrder() {
|
||||
AnalyticsCollector analyticsCollector = new AnalyticsCollector(Clock.DEFAULT);
|
||||
analyticsCollector.setPlayer(
|
||||
new SimpleExoPlayer.Builder(ApplicationProvider.getApplicationContext()).build());
|
||||
AnalyticsListener listener1 = mock(AnalyticsListener.class);
|
||||
AnalyticsListener listener2 =
|
||||
spy(
|
||||
new AnalyticsListener() {
|
||||
@Override
|
||||
public void onPlayerError(EventTime eventTime, ExoPlaybackException error) {
|
||||
analyticsCollector.onSurfaceSizeChanged(/* width= */ 0, /* height= */ 0);
|
||||
}
|
||||
});
|
||||
AnalyticsListener listener3 = mock(AnalyticsListener.class);
|
||||
analyticsCollector.addListener(listener1);
|
||||
analyticsCollector.addListener(listener2);
|
||||
analyticsCollector.addListener(listener3);
|
||||
|
||||
analyticsCollector.onPlayerError(ExoPlaybackException.createForSource(new IOException()));
|
||||
|
||||
InOrder inOrder = Mockito.inOrder(listener1, listener2, listener3);
|
||||
inOrder.verify(listener1).onPlayerError(any(), any());
|
||||
inOrder.verify(listener2).onPlayerError(any(), any());
|
||||
inOrder.verify(listener3).onPlayerError(any(), any());
|
||||
inOrder.verify(listener1).onSurfaceSizeChanged(any(), eq(0), eq(0));
|
||||
inOrder.verify(listener2).onSurfaceSizeChanged(any(), eq(0), eq(0));
|
||||
inOrder.verify(listener3).onSurfaceSizeChanged(any(), eq(0), eq(0));
|
||||
}
|
||||
|
||||
private static TestAnalyticsListener runAnalyticsTest(MediaSource mediaSource) throws Exception {
|
||||
return runAnalyticsTest(mediaSource, /* actionSchedule= */ null);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue