public interface

AnalyticsListener

 androidx.media3.exoplayer.analytics.AnalyticsListener

Subclasses:

EventLogger, MediaMetricsListener, PlaybackStatsListener

Gradle dependencies

compile group: 'androidx.media3', name: 'media3-exoplayer', version: '1.5.0-alpha01'

  • groupId: androidx.media3
  • artifactId: media3-exoplayer
  • version: 1.5.0-alpha01

Artifact androidx.media3:media3-exoplayer:1.5.0-alpha01 it located at Google repository (https://maven.google.com/)

Overview

A listener for analytics events.

All events are recorded with an AnalyticsListener.EventTime specifying the elapsed real time and media time at the time of the event.

All methods have no-op default implementations to allow selective overrides.

Listeners can choose to implement individual events (e.g. AnalyticsListener.onIsPlayingChanged(AnalyticsListener.EventTime, boolean)) or AnalyticsListener.onEvents(Player, AnalyticsListener.Events), which is called after one or more events occurred together.

Summary

Fields
public static final intEVENT_AUDIO_ATTRIBUTES_CHANGED

Audio attributes changed.

public static final intEVENT_AUDIO_CODEC_ERROR

The audio codec encountered an error.

public static final intEVENT_AUDIO_DECODER_INITIALIZED

An audio renderer created a decoder.

public static final intEVENT_AUDIO_DECODER_RELEASED

An audio renderer released a decoder.

public static final intEVENT_AUDIO_DISABLED

An audio renderer was disabled.

public static final intEVENT_AUDIO_ENABLED

An audio renderer was enabled.

public static final intEVENT_AUDIO_INPUT_FORMAT_CHANGED

The format consumed by an audio renderer changed.

public static final intEVENT_AUDIO_POSITION_ADVANCING

The audio position has increased for the first time since the last pause or position reset.

public static final intEVENT_AUDIO_SESSION_ID

An audio session id was set.

public static final intEVENT_AUDIO_SINK_ERROR

The audio sink encountered a non-fatal error.

public static final intEVENT_AUDIO_TRACK_INITIALIZED

An audio track has been initialized.

public static final intEVENT_AUDIO_TRACK_RELEASED

An audio track has been released.

public static final intEVENT_AUDIO_UNDERRUN

An audio underrun occurred.

public static final intEVENT_AVAILABLE_COMMANDS_CHANGED

Player.getAvailableCommands() changed.

public static final intEVENT_BANDWIDTH_ESTIMATE

The bandwidth estimate has been updated.

public static final intEVENT_CUES

Player.getCurrentCues() changed.

public static final intEVENT_DEVICE_INFO_CHANGED

Player.getDeviceInfo() changed.

public static final intEVENT_DEVICE_VOLUME_CHANGED

Player.getDeviceVolume() changed.

public static final intEVENT_DOWNSTREAM_FORMAT_CHANGED

The downstream format sent to renderers changed.

public static final intEVENT_DRM_KEYS_LOADED

DRM keys were loaded.

public static final intEVENT_DRM_KEYS_REMOVED

DRM keys were removed.

public static final intEVENT_DRM_KEYS_RESTORED

DRM keys were restored.

public static final intEVENT_DRM_SESSION_ACQUIRED

A DRM session has been acquired.

public static final intEVENT_DRM_SESSION_MANAGER_ERROR

A non-fatal DRM session manager error occurred.

public static final intEVENT_DRM_SESSION_RELEASED

A DRM session has been released.

public static final intEVENT_DROPPED_VIDEO_FRAMES

Video frames have been dropped.

public static final intEVENT_IS_LOADING_CHANGED

Player.isLoading() ()} changed.

public static final intEVENT_IS_PLAYING_CHANGED

Player.isPlaying() changed.

public static final intEVENT_LOAD_CANCELED

A source canceled loading data.

public static final intEVENT_LOAD_COMPLETED

A source started completed loading data.

public static final intEVENT_LOAD_ERROR

A source had a non-fatal error loading data.

public static final intEVENT_LOAD_STARTED

A source started loading data.

public static final intEVENT_MAX_SEEK_TO_PREVIOUS_POSITION_CHANGED

Player.getMaxSeekToPreviousPosition() changed.

public static final intEVENT_MEDIA_ITEM_TRANSITION

Player.getCurrentMediaItem() changed or the player started repeating the current item.

public static final intEVENT_MEDIA_METADATA_CHANGED

Player.getMediaMetadata() changed.

public static final intEVENT_METADATA

Metadata associated with the current playback time was reported.

public static final intEVENT_PLAY_WHEN_READY_CHANGED

Player.getPlayWhenReady() changed.

public static final intEVENT_PLAYBACK_PARAMETERS_CHANGED

Player.getPlaybackParameters() changed.

public static final intEVENT_PLAYBACK_STATE_CHANGED

Player.getPlaybackState() changed.

public static final intEVENT_PLAYBACK_SUPPRESSION_REASON_CHANGED

Player.getPlaybackSuppressionReason() changed.

public static final intEVENT_PLAYER_ERROR

Player.getPlayerError() changed.

public static final intEVENT_PLAYER_RELEASED

The player was released.

public static final intEVENT_PLAYLIST_METADATA_CHANGED

Player.getPlaylistMetadata() changed.

public static final intEVENT_POSITION_DISCONTINUITY

A position discontinuity occurred.

public static final intEVENT_RENDERED_FIRST_FRAME

The first frame has been rendered since setting the surface, since the renderer was reset or since the stream changed.

public static final intEVENT_RENDERER_READY_CHANGED

A renderer changed its readiness for playback.

public static final intEVENT_REPEAT_MODE_CHANGED

Player.getRepeatMode() changed.

public static final intEVENT_SEEK_BACK_INCREMENT_CHANGED

Player.getSeekBackIncrement() changed.

public static final intEVENT_SEEK_FORWARD_INCREMENT_CHANGED

Player.getSeekForwardIncrement() changed.

public static final intEVENT_SHUFFLE_MODE_ENABLED_CHANGED

Player.getShuffleModeEnabled() changed.

public static final intEVENT_SKIP_SILENCE_ENABLED_CHANGED

Skipping silences was enabled or disabled in the audio stream.

public static final intEVENT_SURFACE_SIZE_CHANGED

The surface size changed.

public static final intEVENT_TIMELINE_CHANGED

Player.getCurrentTimeline() changed.

public static final intEVENT_TRACK_SELECTION_PARAMETERS_CHANGED

Player.getTrackSelectionParameters() changed.

public static final intEVENT_TRACKS_CHANGED

Player.getCurrentTracks() changed.

public static final intEVENT_UPSTREAM_DISCARDED

Data was removed from the end of the media buffer.

public static final intEVENT_VIDEO_CODEC_ERROR

The video codec encountered an error.

public static final intEVENT_VIDEO_DECODER_INITIALIZED

A video renderer created a decoder.

public static final intEVENT_VIDEO_DECODER_RELEASED

A video renderer released a decoder.

public static final intEVENT_VIDEO_DISABLED

A video renderer was disabled.

public static final intEVENT_VIDEO_ENABLED

A video renderer was enabled.

public static final intEVENT_VIDEO_FRAME_PROCESSING_OFFSET

Video frame processing offset data has been reported.

public static final intEVENT_VIDEO_INPUT_FORMAT_CHANGED

The format consumed by a video renderer changed.

public static final intEVENT_VIDEO_SIZE_CHANGED

The video size changed.

public static final intEVENT_VOLUME_CHANGED

The volume changed.

Methods
public voidonAudioAttributesChanged(AnalyticsListener.EventTime eventTime, AudioAttributes audioAttributes)

Called when the audio attributes change.

public voidonAudioCodecError(AnalyticsListener.EventTime eventTime, java.lang.Exception audioCodecError)

Called when an audio decoder encounters an error.

public voidonAudioDecoderInitialized(AnalyticsListener.EventTime eventTime, java.lang.String decoderName, long initializationDurationMs)

public voidonAudioDecoderInitialized(AnalyticsListener.EventTime eventTime, java.lang.String decoderName, long initializedTimestampMs, long initializationDurationMs)

Called when an audio renderer creates a decoder.

public voidonAudioDecoderReleased(AnalyticsListener.EventTime eventTime, java.lang.String decoderName)

Called when an audio renderer releases a decoder.

public voidonAudioDisabled(AnalyticsListener.EventTime eventTime, DecoderCounters decoderCounters)

Called when an audio renderer is disabled.

public voidonAudioEnabled(AnalyticsListener.EventTime eventTime, DecoderCounters decoderCounters)

Called when an audio renderer is enabled.

public voidonAudioInputFormatChanged(AnalyticsListener.EventTime eventTime, Format format, DecoderReuseEvaluation decoderReuseEvaluation)

Called when the format of the media being consumed by an audio renderer changes.

public voidonAudioPositionAdvancing(AnalyticsListener.EventTime eventTime, long playoutStartSystemTimeMs)

Called when the audio position has increased for the first time since the last pause or position reset.

public voidonAudioSessionIdChanged(AnalyticsListener.EventTime eventTime, int audioSessionId)

Called when the audio session ID changes.

public voidonAudioSinkError(AnalyticsListener.EventTime eventTime, java.lang.Exception audioSinkError)

Called when AudioSink has encountered an error.

public voidonAudioTrackInitialized(AnalyticsListener.EventTime eventTime, AudioSink.AudioTrackConfig audioTrackConfig)

Called when an AudioTrack has been initialized.

public voidonAudioTrackReleased(AnalyticsListener.EventTime eventTime, AudioSink.AudioTrackConfig audioTrackConfig)

Called when an AudioTrack has been released.

public voidonAudioUnderrun(AnalyticsListener.EventTime eventTime, int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs)

Called when an audio underrun occurs.

public voidonAvailableCommandsChanged(AnalyticsListener.EventTime eventTime, Player.Commands availableCommands)

Called when the player's available commands changed.

public voidonBandwidthEstimate(AnalyticsListener.EventTime eventTime, int totalLoadTimeMs, long totalBytesLoaded, long bitrateEstimate)

Called when the bandwidth estimate for the current data source has been updated.

public voidonCues(AnalyticsListener.EventTime eventTime, CueGroup cueGroup)

Called when there is a change in the CueGroup.

public voidonCues(AnalyticsListener.EventTime eventTime, java.util.List<Cue> cues)

Called when there is a change in the Cues.

public voidonDeviceInfoChanged(AnalyticsListener.EventTime eventTime, DeviceInfo deviceInfo)

Called when the device information changes

public voidonDeviceVolumeChanged(AnalyticsListener.EventTime eventTime, int volume, boolean muted)

Called when the device volume or mute state changes.

public voidonDownstreamFormatChanged(AnalyticsListener.EventTime eventTime, MediaLoadData mediaLoadData)

Called when the downstream format sent to the renderers changed.

public voidonDrmKeysLoaded(AnalyticsListener.EventTime eventTime)

Called each time drm keys are loaded.

public voidonDrmKeysRemoved(AnalyticsListener.EventTime eventTime)

Called each time offline drm keys are removed.

public voidonDrmKeysRestored(AnalyticsListener.EventTime eventTime)

Called each time offline drm keys are restored.

public voidonDrmSessionAcquired(AnalyticsListener.EventTime eventTime)

public voidonDrmSessionAcquired(AnalyticsListener.EventTime eventTime, int state)

Called each time a drm session is acquired.

public voidonDrmSessionManagerError(AnalyticsListener.EventTime eventTime, java.lang.Exception error)

Called when a drm error occurs.

public voidonDrmSessionReleased(AnalyticsListener.EventTime eventTime)

Called each time a drm session is released.

public voidonDroppedVideoFrames(AnalyticsListener.EventTime eventTime, int droppedFrames, long elapsedMs)

Called after video frames have been dropped.

public voidonEvents(Player player, AnalyticsListener.Events events)

Called after one or more events occurred.

public voidonIsLoadingChanged(AnalyticsListener.EventTime eventTime, boolean isLoading)

Called when the player starts or stops loading data from a source.

public voidonIsPlayingChanged(AnalyticsListener.EventTime eventTime, boolean isPlaying)

Called when the player starts or stops playing.

public voidonLoadCanceled(AnalyticsListener.EventTime eventTime, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData)

Called when a media source canceled loading data.

public voidonLoadCompleted(AnalyticsListener.EventTime eventTime, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData)

Called when a media source completed loading data.

public voidonLoadError(AnalyticsListener.EventTime eventTime, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData, java.io.IOException error, boolean wasCanceled)

Called when a media source loading error occurred.

public voidonLoadingChanged(AnalyticsListener.EventTime eventTime, boolean isLoading)

public voidonLoadStarted(AnalyticsListener.EventTime eventTime, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData)

Called when a media source started loading data.

public voidonMaxSeekToPreviousPositionChanged(AnalyticsListener.EventTime eventTime, long maxSeekToPreviousPositionMs)

Called when the maximum position for which Player.seekToPrevious() seeks to the previous window changes.

public voidonMediaItemTransition(AnalyticsListener.EventTime eventTime, MediaItem mediaItem, int reason)

Called when playback transitions to a different media item.

public voidonMediaMetadataChanged(AnalyticsListener.EventTime eventTime, MediaMetadata mediaMetadata)

Called when the combined MediaMetadata changes.

public voidonMetadata(AnalyticsListener.EventTime eventTime, Metadata metadata)

Called when there is Metadata associated with the current playback time.

public voidonPlaybackParametersChanged(AnalyticsListener.EventTime eventTime, PlaybackParameters playbackParameters)

Called when the playback parameters changed.

public voidonPlaybackStateChanged(AnalyticsListener.EventTime eventTime, int state)

Called when the playback state changed.

public voidonPlaybackSuppressionReasonChanged(AnalyticsListener.EventTime eventTime, int playbackSuppressionReason)

Called when playback suppression reason changed.

public voidonPlayerError(AnalyticsListener.EventTime eventTime, PlaybackException error)

Called when a fatal player error occurred.

public voidonPlayerErrorChanged(AnalyticsListener.EventTime eventTime, PlaybackException error)

Called when the PlaybackException returned by Player.getPlayerError() changes.

public voidonPlayerReleased(AnalyticsListener.EventTime eventTime)

Called when the Player is released.

public voidonPlayerStateChanged(AnalyticsListener.EventTime eventTime, boolean playWhenReady, int playbackState)

public voidonPlaylistMetadataChanged(AnalyticsListener.EventTime eventTime, MediaMetadata playlistMetadata)

Called when the playlist MediaMetadata changes.

public voidonPlayWhenReadyChanged(AnalyticsListener.EventTime eventTime, boolean playWhenReady, int reason)

Called when the value changed that indicates whether playback will proceed when ready.

public voidonPositionDiscontinuity(AnalyticsListener.EventTime eventTime, int reason)

public voidonPositionDiscontinuity(AnalyticsListener.EventTime eventTime, Player.PositionInfo oldPosition, Player.PositionInfo newPosition, int reason)

Called when a position discontinuity occurred.

public voidonRenderedFirstFrame(AnalyticsListener.EventTime eventTime, java.lang.Object output, long renderTimeMs)

Called when a frame is rendered for the first time since setting the surface, or since the renderer was reset, or since the stream being rendered was changed.

public voidonRendererReadyChanged(AnalyticsListener.EventTime eventTime, int rendererIndex, int rendererTrackType, boolean isRendererReady)

Called each time a renderer starts or stops allowing playback to be ready.

public voidonRepeatModeChanged(AnalyticsListener.EventTime eventTime, int repeatMode)

Called when the repeat mode changed.

public voidonSeekBackIncrementChanged(AnalyticsListener.EventTime eventTime, long seekBackIncrementMs)

Called when the seek back increment changed.

public voidonSeekForwardIncrementChanged(AnalyticsListener.EventTime eventTime, long seekForwardIncrementMs)

Called when the seek forward increment changed.

public voidonSeekStarted(AnalyticsListener.EventTime eventTime)

public voidonShuffleModeChanged(AnalyticsListener.EventTime eventTime, boolean shuffleModeEnabled)

Called when the shuffle mode changed.

public voidonSkipSilenceEnabledChanged(AnalyticsListener.EventTime eventTime, boolean skipSilenceEnabled)

Called when skipping silences is enabled or disabled in the audio stream.

public voidonSurfaceSizeChanged(AnalyticsListener.EventTime eventTime, int width, int height)

Called when the output surface size changed.

public voidonTimelineChanged(AnalyticsListener.EventTime eventTime, int reason)

Called when the timeline changed.

public voidonTracksChanged(AnalyticsListener.EventTime eventTime, Tracks tracks)

Called when the tracks change.

public voidonTrackSelectionParametersChanged(AnalyticsListener.EventTime eventTime, TrackSelectionParameters trackSelectionParameters)

Called when track selection parameters change.

public voidonUpstreamDiscarded(AnalyticsListener.EventTime eventTime, MediaLoadData mediaLoadData)

Called when data is removed from the back of a media buffer, typically so that it can be re-buffered in a different format.

public voidonVideoCodecError(AnalyticsListener.EventTime eventTime, java.lang.Exception videoCodecError)

Called when a video decoder encounters an error.

public voidonVideoDecoderInitialized(AnalyticsListener.EventTime eventTime, java.lang.String decoderName, long initializationDurationMs)

public voidonVideoDecoderInitialized(AnalyticsListener.EventTime eventTime, java.lang.String decoderName, long initializedTimestampMs, long initializationDurationMs)

Called when a video renderer creates a decoder.

public voidonVideoDecoderReleased(AnalyticsListener.EventTime eventTime, java.lang.String decoderName)

Called when a video renderer releases a decoder.

public voidonVideoDisabled(AnalyticsListener.EventTime eventTime, DecoderCounters decoderCounters)

Called when a video renderer is disabled.

public voidonVideoEnabled(AnalyticsListener.EventTime eventTime, DecoderCounters decoderCounters)

Called when a video renderer is enabled.

public voidonVideoFrameProcessingOffset(AnalyticsListener.EventTime eventTime, long totalProcessingOffsetUs, int frameCount)

Called when there is an update to the video frame processing offset reported by a video renderer.

public voidonVideoInputFormatChanged(AnalyticsListener.EventTime eventTime, Format format, DecoderReuseEvaluation decoderReuseEvaluation)

Called when the format of the media being consumed by a video renderer changes.

public voidonVideoSizeChanged(AnalyticsListener.EventTime eventTime, int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio)

public voidonVideoSizeChanged(AnalyticsListener.EventTime eventTime, VideoSize videoSize)

Called before a frame is rendered for the first time since setting the surface, and each time there's a change in the size or pixel aspect ratio of the video being rendered.

public voidonVolumeChanged(AnalyticsListener.EventTime eventTime, float volume)

Called when the volume changes.

Fields

public static final int EVENT_TIMELINE_CHANGED

Player.getCurrentTimeline() changed.

public static final int EVENT_MEDIA_ITEM_TRANSITION

Player.getCurrentMediaItem() changed or the player started repeating the current item.

public static final int EVENT_TRACKS_CHANGED

Player.getCurrentTracks() changed.

public static final int EVENT_IS_LOADING_CHANGED

Player.isLoading() ()} changed.

public static final int EVENT_PLAYBACK_STATE_CHANGED

Player.getPlaybackState() changed.

public static final int EVENT_PLAY_WHEN_READY_CHANGED

Player.getPlayWhenReady() changed.

public static final int EVENT_PLAYBACK_SUPPRESSION_REASON_CHANGED

Player.getPlaybackSuppressionReason() changed.

public static final int EVENT_IS_PLAYING_CHANGED

Player.isPlaying() changed.

public static final int EVENT_REPEAT_MODE_CHANGED

Player.getRepeatMode() changed.

public static final int EVENT_SHUFFLE_MODE_ENABLED_CHANGED

Player.getShuffleModeEnabled() changed.

public static final int EVENT_PLAYER_ERROR

Player.getPlayerError() changed.

public static final int EVENT_POSITION_DISCONTINUITY

A position discontinuity occurred. See .

public static final int EVENT_PLAYBACK_PARAMETERS_CHANGED

Player.getPlaybackParameters() changed.

public static final int EVENT_AVAILABLE_COMMANDS_CHANGED

Player.getAvailableCommands() changed.

public static final int EVENT_MEDIA_METADATA_CHANGED

Player.getMediaMetadata() changed.

public static final int EVENT_PLAYLIST_METADATA_CHANGED

Player.getPlaylistMetadata() changed.

public static final int EVENT_SEEK_BACK_INCREMENT_CHANGED

Player.getSeekBackIncrement() changed.

public static final int EVENT_SEEK_FORWARD_INCREMENT_CHANGED

Player.getSeekForwardIncrement() changed.

public static final int EVENT_MAX_SEEK_TO_PREVIOUS_POSITION_CHANGED

Player.getMaxSeekToPreviousPosition() changed.

public static final int EVENT_TRACK_SELECTION_PARAMETERS_CHANGED

Player.getTrackSelectionParameters() changed.

public static final int EVENT_AUDIO_ATTRIBUTES_CHANGED

Audio attributes changed.

public static final int EVENT_AUDIO_SESSION_ID

An audio session id was set.

public static final int EVENT_VOLUME_CHANGED

The volume changed.

public static final int EVENT_SKIP_SILENCE_ENABLED_CHANGED

Skipping silences was enabled or disabled in the audio stream.

public static final int EVENT_SURFACE_SIZE_CHANGED

The surface size changed.

public static final int EVENT_VIDEO_SIZE_CHANGED

The video size changed.

public static final int EVENT_RENDERED_FIRST_FRAME

The first frame has been rendered since setting the surface, since the renderer was reset or since the stream changed.

public static final int EVENT_METADATA

Metadata associated with the current playback time was reported.

public static final int EVENT_CUES

Player.getCurrentCues() changed.

public static final int EVENT_DEVICE_INFO_CHANGED

Player.getDeviceInfo() changed.

public static final int EVENT_DEVICE_VOLUME_CHANGED

Player.getDeviceVolume() changed.

public static final int EVENT_LOAD_STARTED

A source started loading data.

public static final int EVENT_LOAD_COMPLETED

A source started completed loading data.

public static final int EVENT_LOAD_CANCELED

A source canceled loading data.

public static final int EVENT_LOAD_ERROR

A source had a non-fatal error loading data.

public static final int EVENT_DOWNSTREAM_FORMAT_CHANGED

The downstream format sent to renderers changed.

public static final int EVENT_UPSTREAM_DISCARDED

Data was removed from the end of the media buffer.

public static final int EVENT_BANDWIDTH_ESTIMATE

The bandwidth estimate has been updated.

public static final int EVENT_AUDIO_ENABLED

An audio renderer was enabled.

public static final int EVENT_AUDIO_DECODER_INITIALIZED

An audio renderer created a decoder.

public static final int EVENT_AUDIO_INPUT_FORMAT_CHANGED

The format consumed by an audio renderer changed.

public static final int EVENT_AUDIO_POSITION_ADVANCING

The audio position has increased for the first time since the last pause or position reset.

public static final int EVENT_AUDIO_UNDERRUN

An audio underrun occurred.

public static final int EVENT_AUDIO_DECODER_RELEASED

An audio renderer released a decoder.

public static final int EVENT_AUDIO_DISABLED

An audio renderer was disabled.

public static final int EVENT_AUDIO_SINK_ERROR

The audio sink encountered a non-fatal error.

public static final int EVENT_VIDEO_ENABLED

A video renderer was enabled.

public static final int EVENT_VIDEO_DECODER_INITIALIZED

A video renderer created a decoder.

public static final int EVENT_VIDEO_INPUT_FORMAT_CHANGED

The format consumed by a video renderer changed.

public static final int EVENT_DROPPED_VIDEO_FRAMES

Video frames have been dropped.

public static final int EVENT_VIDEO_DECODER_RELEASED

A video renderer released a decoder.

public static final int EVENT_VIDEO_DISABLED

A video renderer was disabled.

public static final int EVENT_VIDEO_FRAME_PROCESSING_OFFSET

Video frame processing offset data has been reported.

public static final int EVENT_DRM_SESSION_ACQUIRED

A DRM session has been acquired.

public static final int EVENT_DRM_KEYS_LOADED

DRM keys were loaded.

public static final int EVENT_DRM_SESSION_MANAGER_ERROR

A non-fatal DRM session manager error occurred.

public static final int EVENT_DRM_KEYS_RESTORED

DRM keys were restored.

public static final int EVENT_DRM_KEYS_REMOVED

DRM keys were removed.

public static final int EVENT_DRM_SESSION_RELEASED

A DRM session has been released.

public static final int EVENT_PLAYER_RELEASED

The player was released.

public static final int EVENT_AUDIO_CODEC_ERROR

The audio codec encountered an error.

public static final int EVENT_VIDEO_CODEC_ERROR

The video codec encountered an error.

public static final int EVENT_AUDIO_TRACK_INITIALIZED

An audio track has been initialized.

public static final int EVENT_AUDIO_TRACK_RELEASED

An audio track has been released.

public static final int EVENT_RENDERER_READY_CHANGED

A renderer changed its readiness for playback.

Methods

public void onPlayerStateChanged(AnalyticsListener.EventTime eventTime, boolean playWhenReady, int playbackState)

Deprecated: Use AnalyticsListener.onPlaybackStateChanged(AnalyticsListener.EventTime, int) and AnalyticsListener.onPlayWhenReadyChanged(AnalyticsListener.EventTime, boolean, int) instead.

public void onPlaybackStateChanged(AnalyticsListener.EventTime eventTime, int state)

Called when the playback state changed.

Parameters:

eventTime: The event time.
state: The new .

public void onPlayWhenReadyChanged(AnalyticsListener.EventTime eventTime, boolean playWhenReady, int reason)

Called when the value changed that indicates whether playback will proceed when ready.

Parameters:

eventTime: The event time.
playWhenReady: Whether playback will proceed when ready.
reason: The of the change.

public void onPlaybackSuppressionReasonChanged(AnalyticsListener.EventTime eventTime, int playbackSuppressionReason)

Called when playback suppression reason changed.

Parameters:

eventTime: The event time.
playbackSuppressionReason: The new Player.PlaybackSuppressionReason.

public void onIsPlayingChanged(AnalyticsListener.EventTime eventTime, boolean isPlaying)

Called when the player starts or stops playing.

Parameters:

eventTime: The event time.
isPlaying: Whether the player is playing.

public void onTimelineChanged(AnalyticsListener.EventTime eventTime, int reason)

Called when the timeline changed.

Parameters:

eventTime: The event time.
reason: The reason for the timeline change.

public void onMediaItemTransition(AnalyticsListener.EventTime eventTime, MediaItem mediaItem, int reason)

Called when playback transitions to a different media item.

Parameters:

eventTime: The event time.
mediaItem: The media item.
reason: The reason for the media item transition.

public void onPositionDiscontinuity(AnalyticsListener.EventTime eventTime, int reason)

Deprecated: Use AnalyticsListener.onPositionDiscontinuity(AnalyticsListener.EventTime, Player.PositionInfo, Player.PositionInfo, int) instead.

public void onPositionDiscontinuity(AnalyticsListener.EventTime eventTime, Player.PositionInfo oldPosition, Player.PositionInfo newPosition, int reason)

Called when a position discontinuity occurred.

Parameters:

eventTime: The event time.
oldPosition: The position before the discontinuity.
newPosition: The position after the discontinuity.
reason: The reason for the position discontinuity.

public void onSeekStarted(AnalyticsListener.EventTime eventTime)

Deprecated: Use AnalyticsListener.onPositionDiscontinuity(AnalyticsListener.EventTime, Player.PositionInfo, Player.PositionInfo, int) instead, listening to changes with Player.DISCONTINUITY_REASON_SEEK.

public void onPlaybackParametersChanged(AnalyticsListener.EventTime eventTime, PlaybackParameters playbackParameters)

Called when the playback parameters changed.

Parameters:

eventTime: The event time.
playbackParameters: The new playback parameters.

public void onSeekBackIncrementChanged(AnalyticsListener.EventTime eventTime, long seekBackIncrementMs)

Called when the seek back increment changed.

Parameters:

eventTime: The event time.
seekBackIncrementMs: The seek back increment, in milliseconds.

public void onSeekForwardIncrementChanged(AnalyticsListener.EventTime eventTime, long seekForwardIncrementMs)

Called when the seek forward increment changed.

Parameters:

eventTime: The event time.
seekForwardIncrementMs: The seek forward increment, in milliseconds.

public void onMaxSeekToPreviousPositionChanged(AnalyticsListener.EventTime eventTime, long maxSeekToPreviousPositionMs)

Called when the maximum position for which Player.seekToPrevious() seeks to the previous window changes.

Parameters:

eventTime: The event time.
maxSeekToPreviousPositionMs: The maximum seek to previous position, in milliseconds.

public void onRepeatModeChanged(AnalyticsListener.EventTime eventTime, int repeatMode)

Called when the repeat mode changed.

Parameters:

eventTime: The event time.
repeatMode: The new repeat mode.

public void onShuffleModeChanged(AnalyticsListener.EventTime eventTime, boolean shuffleModeEnabled)

Called when the shuffle mode changed.

Parameters:

eventTime: The event time.
shuffleModeEnabled: Whether the shuffle mode is enabled.

public void onIsLoadingChanged(AnalyticsListener.EventTime eventTime, boolean isLoading)

Called when the player starts or stops loading data from a source.

Parameters:

eventTime: The event time.
isLoading: Whether the player is loading.

public void onLoadingChanged(AnalyticsListener.EventTime eventTime, boolean isLoading)

Deprecated: Use AnalyticsListener.onIsLoadingChanged(AnalyticsListener.EventTime, boolean) instead.

public void onAvailableCommandsChanged(AnalyticsListener.EventTime eventTime, Player.Commands availableCommands)

Called when the player's available commands changed.

Parameters:

eventTime: The event time.
availableCommands: The available commands.

public void onPlayerError(AnalyticsListener.EventTime eventTime, PlaybackException error)

Called when a fatal player error occurred.

Implementations of Player may pass an instance of a subclass of PlaybackException to this method in order to include more information about the error.

Parameters:

eventTime: The event time.
error: The error.

public void onPlayerErrorChanged(AnalyticsListener.EventTime eventTime, PlaybackException error)

Called when the PlaybackException returned by Player.getPlayerError() changes.

Implementations of Player may pass an instance of a subclass of PlaybackException to this method in order to include more information about the error.

Parameters:

eventTime: The event time.
error: The new error, or null if the error is being cleared.

public void onTracksChanged(AnalyticsListener.EventTime eventTime, Tracks tracks)

Called when the tracks change.

Parameters:

eventTime: The event time.
tracks: The tracks. Never null, but may be of length zero.

public void onTrackSelectionParametersChanged(AnalyticsListener.EventTime eventTime, TrackSelectionParameters trackSelectionParameters)

Called when track selection parameters change.

Parameters:

eventTime: The event time.
trackSelectionParameters: The new TrackSelectionParameters.

public void onMediaMetadataChanged(AnalyticsListener.EventTime eventTime, MediaMetadata mediaMetadata)

Called when the combined MediaMetadata changes.

The provided MediaMetadata is a combination of the MediaItem.mediaMetadata and the static and dynamic metadata from the track selections' formats and MetadataOutput.onMetadata(Metadata).

Parameters:

eventTime: The event time.
mediaMetadata: The combined MediaMetadata.

public void onPlaylistMetadataChanged(AnalyticsListener.EventTime eventTime, MediaMetadata playlistMetadata)

Called when the playlist MediaMetadata changes.

Parameters:

eventTime: The event time.
playlistMetadata: The playlist MediaMetadata.

public void onLoadStarted(AnalyticsListener.EventTime eventTime, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData)

Called when a media source started loading data.

Parameters:

eventTime: The event time.
loadEventInfo: The LoadEventInfo defining the load event.
mediaLoadData: The MediaLoadData defining the data being loaded.

public void onLoadCompleted(AnalyticsListener.EventTime eventTime, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData)

Called when a media source completed loading data.

Parameters:

eventTime: The event time.
loadEventInfo: The LoadEventInfo defining the load event.
mediaLoadData: The MediaLoadData defining the data being loaded.

public void onLoadCanceled(AnalyticsListener.EventTime eventTime, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData)

Called when a media source canceled loading data.

Parameters:

eventTime: The event time.
loadEventInfo: The LoadEventInfo defining the load event.
mediaLoadData: The MediaLoadData defining the data being loaded.

public void onLoadError(AnalyticsListener.EventTime eventTime, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData, java.io.IOException error, boolean wasCanceled)

Called when a media source loading error occurred.

This method being called does not indicate that playback has failed, or that it will fail. The player may be able to recover from the error. Hence applications should not implement this method to display a user visible error or initiate an application level retry. is the appropriate place to implement such behavior. This method is called to provide the application with an opportunity to log the error if it wishes to do so.

Parameters:

eventTime: The event time.
loadEventInfo: The LoadEventInfo defining the load event.
mediaLoadData: The MediaLoadData defining the data being loaded.
error: The load error.
wasCanceled: Whether the load was canceled as a result of the error.

public void onDownstreamFormatChanged(AnalyticsListener.EventTime eventTime, MediaLoadData mediaLoadData)

Called when the downstream format sent to the renderers changed.

Parameters:

eventTime: The event time.
mediaLoadData: The MediaLoadData defining the newly selected media data.

public void onUpstreamDiscarded(AnalyticsListener.EventTime eventTime, MediaLoadData mediaLoadData)

Called when data is removed from the back of a media buffer, typically so that it can be re-buffered in a different format.

Parameters:

eventTime: The event time.
mediaLoadData: The MediaLoadData defining the media being discarded.

public void onBandwidthEstimate(AnalyticsListener.EventTime eventTime, int totalLoadTimeMs, long totalBytesLoaded, long bitrateEstimate)

Called when the bandwidth estimate for the current data source has been updated.

Parameters:

eventTime: The event time.
totalLoadTimeMs: The total time spend loading this update is based on, in milliseconds.
totalBytesLoaded: The total bytes loaded this update is based on.
bitrateEstimate: The bandwidth estimate, in bits per second.

public void onMetadata(AnalyticsListener.EventTime eventTime, Metadata metadata)

Called when there is Metadata associated with the current playback time.

Parameters:

eventTime: The event time.
metadata: The metadata.

public void onCues(AnalyticsListener.EventTime eventTime, java.util.List<Cue> cues)

Deprecated: Use AnalyticsListener.onCues(AnalyticsListener.EventTime, CueGroup) instead.

Called when there is a change in the Cues.

Both AnalyticsListener.onCues(AnalyticsListener.EventTime, List) and AnalyticsListener.onCues(AnalyticsListener.EventTime, CueGroup) are called when there is a change in the cues. You should only implement one or the other.

Parameters:

eventTime: The event time.
cues: The Cues.

public void onCues(AnalyticsListener.EventTime eventTime, CueGroup cueGroup)

Called when there is a change in the CueGroup.

Both AnalyticsListener.onCues(AnalyticsListener.EventTime, List) and AnalyticsListener.onCues(AnalyticsListener.EventTime, CueGroup) are called when there is a change in the cues. You should only implement one or the other.

Parameters:

eventTime: The event time.
cueGroup: The CueGroup.

public void onAudioEnabled(AnalyticsListener.EventTime eventTime, DecoderCounters decoderCounters)

Called when an audio renderer is enabled.

Parameters:

eventTime: The event time.
decoderCounters: DecoderCounters that will be updated by the renderer for as long as it remains enabled.

public void onAudioDecoderInitialized(AnalyticsListener.EventTime eventTime, java.lang.String decoderName, long initializedTimestampMs, long initializationDurationMs)

Called when an audio renderer creates a decoder.

Parameters:

eventTime: The event time.
decoderName: The decoder that was created.
initializedTimestampMs: when initialization finished.
initializationDurationMs: The time taken to initialize the decoder in milliseconds.

public void onAudioDecoderInitialized(AnalyticsListener.EventTime eventTime, java.lang.String decoderName, long initializationDurationMs)

Deprecated: Use AnalyticsListener.onAudioDecoderInitialized(AnalyticsListener.EventTime, String, long, long).

public void onAudioInputFormatChanged(AnalyticsListener.EventTime eventTime, Format format, DecoderReuseEvaluation decoderReuseEvaluation)

Called when the format of the media being consumed by an audio renderer changes.

Parameters:

eventTime: The event time.
format: The new format.
decoderReuseEvaluation: The result of the evaluation to determine whether an existing decoder instance can be reused for the new format, or null if the renderer did not have a decoder.

public void onAudioPositionAdvancing(AnalyticsListener.EventTime eventTime, long playoutStartSystemTimeMs)

Called when the audio position has increased for the first time since the last pause or position reset.

Parameters:

eventTime: The event time.
playoutStartSystemTimeMs: The approximate derived currentTimeMillis at which playout started.

public void onAudioUnderrun(AnalyticsListener.EventTime eventTime, int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs)

Called when an audio underrun occurs.

Parameters:

eventTime: The event time.
bufferSize: The size of the audio output buffer, in bytes.
bufferSizeMs: The size of the audio output buffer, in milliseconds, if it contains PCM encoded audio. C.TIME_UNSET if the output buffer contains non-PCM encoded audio.
elapsedSinceLastFeedMs: The time since audio was last written to the output buffer.

public void onAudioDecoderReleased(AnalyticsListener.EventTime eventTime, java.lang.String decoderName)

Called when an audio renderer releases a decoder.

Parameters:

eventTime: The event time.
decoderName: The decoder that was released.

public void onAudioDisabled(AnalyticsListener.EventTime eventTime, DecoderCounters decoderCounters)

Called when an audio renderer is disabled.

Parameters:

eventTime: The event time.
decoderCounters: DecoderCounters that were updated by the renderer.

public void onAudioSessionIdChanged(AnalyticsListener.EventTime eventTime, int audioSessionId)

Called when the audio session ID changes.

Parameters:

eventTime: The event time.
audioSessionId: The audio session ID.

public void onAudioAttributesChanged(AnalyticsListener.EventTime eventTime, AudioAttributes audioAttributes)

Called when the audio attributes change.

Parameters:

eventTime: The event time.
audioAttributes: The audio attributes.

public void onSkipSilenceEnabledChanged(AnalyticsListener.EventTime eventTime, boolean skipSilenceEnabled)

Called when skipping silences is enabled or disabled in the audio stream.

Parameters:

eventTime: The event time.
skipSilenceEnabled: Whether skipping silences in the audio stream is enabled.

public void onAudioSinkError(AnalyticsListener.EventTime eventTime, java.lang.Exception audioSinkError)

Called when AudioSink has encountered an error.

This method being called does not indicate that playback has failed, or that it will fail. The player may be able to recover from the error. Hence applications should not implement this method to display a user visible error or initiate an application level retry. is the appropriate place to implement such behavior. This method is called to provide the application with an opportunity to log the error if it wishes to do so.

Parameters:

eventTime: The event time.
audioSinkError: The error that occurred. Typically an , a , or an .

public void onAudioCodecError(AnalyticsListener.EventTime eventTime, java.lang.Exception audioCodecError)

Called when an audio decoder encounters an error.

This method being called does not indicate that playback has failed, or that it will fail. The player may be able to recover from the error. Hence applications should not implement this method to display a user visible error or initiate an application level retry. is the appropriate place to implement such behavior. This method is called to provide the application with an opportunity to log the error if it wishes to do so.

Parameters:

eventTime: The event time.
audioCodecError: The error. Typically a if the renderer uses MediaCodec, or a DecoderException if the renderer uses a software decoder.

public void onAudioTrackInitialized(AnalyticsListener.EventTime eventTime, AudioSink.AudioTrackConfig audioTrackConfig)

Called when an AudioTrack has been initialized.

Parameters:

eventTime: The event time.
audioTrackConfig: The of the initialized AudioTrack.

public void onAudioTrackReleased(AnalyticsListener.EventTime eventTime, AudioSink.AudioTrackConfig audioTrackConfig)

Called when an AudioTrack has been released.

Parameters:

eventTime: The event time.
audioTrackConfig: The of the released AudioTrack.

public void onVolumeChanged(AnalyticsListener.EventTime eventTime, float volume)

Called when the volume changes.

Parameters:

eventTime: The event time.
volume: The new volume, with 0 being silence and 1 being unity gain.

public void onDeviceInfoChanged(AnalyticsListener.EventTime eventTime, DeviceInfo deviceInfo)

Called when the device information changes

Parameters:

eventTime: The event time.
deviceInfo: The new DeviceInfo.

public void onDeviceVolumeChanged(AnalyticsListener.EventTime eventTime, int volume, boolean muted)

Called when the device volume or mute state changes.

Parameters:

eventTime: The event time.
volume: The new device volume, with 0 being silence and 1 being unity gain.
muted: Whether the device is muted.

public void onVideoEnabled(AnalyticsListener.EventTime eventTime, DecoderCounters decoderCounters)

Called when a video renderer is enabled.

Parameters:

eventTime: The event time.
decoderCounters: DecoderCounters that will be updated by the renderer for as long as it remains enabled.

public void onVideoDecoderInitialized(AnalyticsListener.EventTime eventTime, java.lang.String decoderName, long initializedTimestampMs, long initializationDurationMs)

Called when a video renderer creates a decoder.

Parameters:

eventTime: The event time.
decoderName: The decoder that was created.
initializedTimestampMs: when initialization finished.
initializationDurationMs: The time taken to initialize the decoder in milliseconds.

public void onVideoDecoderInitialized(AnalyticsListener.EventTime eventTime, java.lang.String decoderName, long initializationDurationMs)

Deprecated: Use AnalyticsListener.onVideoDecoderInitialized(AnalyticsListener.EventTime, String, long, long).

public void onVideoInputFormatChanged(AnalyticsListener.EventTime eventTime, Format format, DecoderReuseEvaluation decoderReuseEvaluation)

Called when the format of the media being consumed by a video renderer changes.

Parameters:

eventTime: The event time.
format: The new format.
decoderReuseEvaluation: The result of the evaluation to determine whether an existing decoder instance can be reused for the new format, or null if the renderer did not have a decoder.

public void onDroppedVideoFrames(AnalyticsListener.EventTime eventTime, int droppedFrames, long elapsedMs)

Called after video frames have been dropped.

Parameters:

eventTime: The event time.
droppedFrames: The number of dropped frames since the last call to this method.
elapsedMs: The duration in milliseconds over which the frames were dropped. This duration is timed from when the renderer was started or from when dropped frames were last reported (whichever was more recent), and not from when the first of the reported drops occurred.

public void onVideoDecoderReleased(AnalyticsListener.EventTime eventTime, java.lang.String decoderName)

Called when a video renderer releases a decoder.

Parameters:

eventTime: The event time.
decoderName: The decoder that was released.

public void onVideoDisabled(AnalyticsListener.EventTime eventTime, DecoderCounters decoderCounters)

Called when a video renderer is disabled.

Parameters:

eventTime: The event time.
decoderCounters: DecoderCounters that were updated by the renderer.

public void onVideoFrameProcessingOffset(AnalyticsListener.EventTime eventTime, long totalProcessingOffsetUs, int frameCount)

Called when there is an update to the video frame processing offset reported by a video renderer.

The processing offset for a video frame is the difference between the time at which the frame became available to render, and the time at which it was scheduled to be rendered. A positive value indicates the frame became available early enough, whereas a negative value indicates that the frame wasn't available until after the time at which it should have been rendered.

Parameters:

eventTime: The event time.
totalProcessingOffsetUs: The sum of the video frame processing offsets for frames rendered since the last call to this method.
frameCount: The number to samples included in totalProcessingOffsetUs.

public void onVideoCodecError(AnalyticsListener.EventTime eventTime, java.lang.Exception videoCodecError)

Called when a video decoder encounters an error.

This method being called does not indicate that playback has failed, or that it will fail. The player may be able to recover from the error. Hence applications should not implement this method to display a user visible error or initiate an application level retry. is the appropriate place to implement such behavior. This method is called to provide the application with an opportunity to log the error if it wishes to do so.

Parameters:

eventTime: The event time.
videoCodecError: The error. Typically a if the renderer uses MediaCodec, or a DecoderException if the renderer uses a software decoder.

public void onRenderedFirstFrame(AnalyticsListener.EventTime eventTime, java.lang.Object output, long renderTimeMs)

Called when a frame is rendered for the first time since setting the surface, or since the renderer was reset, or since the stream being rendered was changed.

Parameters:

eventTime: The event time.
output: The output to which a frame has been rendered. Normally a , however may also be other output types (e.g., a VideoDecoderOutputBufferRenderer).
renderTimeMs: when the first frame was rendered.

public void onVideoSizeChanged(AnalyticsListener.EventTime eventTime, VideoSize videoSize)

Called before a frame is rendered for the first time since setting the surface, and each time there's a change in the size or pixel aspect ratio of the video being rendered.

Parameters:

eventTime: The event time.
videoSize: The new size of the video.

public void onVideoSizeChanged(AnalyticsListener.EventTime eventTime, int width, int height, int unappliedRotationDegrees, float pixelWidthHeightRatio)

Deprecated: Implement AnalyticsListener.onVideoSizeChanged(AnalyticsListener.EventTime, VideoSize) instead.

public void onSurfaceSizeChanged(AnalyticsListener.EventTime eventTime, int width, int height)

Called when the output surface size changed.

Parameters:

eventTime: The event time.
width: The surface width in pixels. May be C.LENGTH_UNSET if unknown, or 0 if the video is not rendered onto a surface.
height: The surface height in pixels. May be C.LENGTH_UNSET if unknown, or 0 if the video is not rendered onto a surface.

public void onDrmSessionAcquired(AnalyticsListener.EventTime eventTime)

Deprecated: Implement AnalyticsListener.onDrmSessionAcquired(AnalyticsListener.EventTime, int) instead.

public void onDrmSessionAcquired(AnalyticsListener.EventTime eventTime, int state)

Called each time a drm session is acquired.

Parameters:

eventTime: The event time.
state: The of the session when the acquisition completed.

public void onDrmKeysLoaded(AnalyticsListener.EventTime eventTime)

Called each time drm keys are loaded.

Parameters:

eventTime: The event time.

public void onDrmSessionManagerError(AnalyticsListener.EventTime eventTime, java.lang.Exception error)

Called when a drm error occurs.

This method being called does not indicate that playback has failed, or that it will fail. The player may be able to recover from the error. Hence applications should not implement this method to display a user visible error or initiate an application level retry. is the appropriate place to implement such behavior. This method is called to provide the application with an opportunity to log the error if it wishes to do so.

Parameters:

eventTime: The event time.
error: The error.

public void onDrmKeysRestored(AnalyticsListener.EventTime eventTime)

Called each time offline drm keys are restored.

Parameters:

eventTime: The event time.

public void onDrmKeysRemoved(AnalyticsListener.EventTime eventTime)

Called each time offline drm keys are removed.

Parameters:

eventTime: The event time.

public void onDrmSessionReleased(AnalyticsListener.EventTime eventTime)

Called each time a drm session is released.

Parameters:

eventTime: The event time.

public void onRendererReadyChanged(AnalyticsListener.EventTime eventTime, int rendererIndex, int rendererTrackType, boolean isRendererReady)

Called each time a renderer starts or stops allowing playback to be ready.

Parameters:

eventTime: The event time.
rendererIndex: The index of the renderer in the ExoPlayer instance.
rendererTrackType: The of the renderer.
isRendererReady: Whether the renderer allows playback to be ready.

public void onPlayerReleased(AnalyticsListener.EventTime eventTime)

Called when the Player is released.

Parameters:

eventTime: The event time.

public void onEvents(Player player, AnalyticsListener.Events events)

Called after one or more events occurred.

State changes and events that happen within one message queue iteration are reported together and only after all individual callbacks were triggered.

Listeners should prefer this method over individual callbacks in the following cases:

Parameters:

player: The Player.
events: The AnalyticsListener.Events that occurred in this iteration.

Source

/*
 * 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 androidx.media3.exoplayer.analytics;

import static androidx.media3.common.util.Assertions.checkNotNull;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.LOCAL_VARIABLE;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE_USE;

import android.media.AudioTrack;
import android.media.MediaCodec;
import android.media.MediaCodec.CodecException;
import android.os.Looper;
import android.os.SystemClock;
import android.util.SparseArray;
import android.view.Surface;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
import androidx.media3.common.AudioAttributes;
import androidx.media3.common.C;
import androidx.media3.common.DeviceInfo;
import androidx.media3.common.FlagSet;
import androidx.media3.common.Format;
import androidx.media3.common.MediaItem;
import androidx.media3.common.MediaMetadata;
import androidx.media3.common.Metadata;
import androidx.media3.common.PlaybackException;
import androidx.media3.common.PlaybackParameters;
import androidx.media3.common.Player;
import androidx.media3.common.Player.DiscontinuityReason;
import androidx.media3.common.Player.PlaybackSuppressionReason;
import androidx.media3.common.Player.TimelineChangeReason;
import androidx.media3.common.Timeline;
import androidx.media3.common.TrackSelectionParameters;
import androidx.media3.common.Tracks;
import androidx.media3.common.VideoSize;
import androidx.media3.common.text.Cue;
import androidx.media3.common.text.CueGroup;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.decoder.DecoderException;
import androidx.media3.exoplayer.DecoderCounters;
import androidx.media3.exoplayer.DecoderReuseEvaluation;
import androidx.media3.exoplayer.audio.AudioSink;
import androidx.media3.exoplayer.drm.DrmSession;
import androidx.media3.exoplayer.metadata.MetadataOutput;
import androidx.media3.exoplayer.source.LoadEventInfo;
import androidx.media3.exoplayer.source.MediaLoadData;
import androidx.media3.exoplayer.source.MediaSource.MediaPeriodId;
import androidx.media3.exoplayer.trackselection.TrackSelection;
import androidx.media3.exoplayer.video.VideoDecoderOutputBufferRenderer;
import com.google.common.base.Objects;
import java.io.IOException;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.List;

/**
 * A listener for analytics events.
 *
 * <p>All events are recorded with an {@link EventTime} specifying the elapsed real time and media
 * time at the time of the event.
 *
 * <p>All methods have no-op default implementations to allow selective overrides.
 *
 * <p>Listeners can choose to implement individual events (e.g. {@link
 * #onIsPlayingChanged(EventTime, boolean)}) or {@link #onEvents(Player, Events)}, which is called
 * after one or more events occurred together.
 */
public interface AnalyticsListener {

  /** A set of {@link EventFlags}. */
  @UnstableApi
  final class Events {

    private final FlagSet flags;
    private final SparseArray<EventTime> eventTimes;

    /**
     * Creates an instance.
     *
     * @param flags The {@link FlagSet} containing the {@link EventFlags} in the set.
     * @param eventTimes A map from {@link EventFlags} to {@link EventTime}. Must at least contain
     *     all the events recorded in {@code flags}. Events that are not recorded in {@code flags}
     *     are ignored.
     */
    public Events(FlagSet flags, SparseArray<EventTime> eventTimes) {
      this.flags = flags;
      SparseArray<EventTime> flagsToTimes = new SparseArray<>(/* initialCapacity= */ flags.size());
      for (int i = 0; i < flags.size(); i++) {
        @EventFlags int eventFlag = flags.get(i);
        flagsToTimes.append(eventFlag, checkNotNull(eventTimes.get(eventFlag)));
      }
      this.eventTimes = flagsToTimes;
    }

    /**
     * Returns the {@link EventTime} for the specified event.
     *
     * @param event The {@link EventFlags event}.
     * @return The {@link EventTime} of this event.
     */
    public EventTime getEventTime(@EventFlags int event) {
      return checkNotNull(eventTimes.get(event));
    }

    /**
     * Returns whether the given event occurred.
     *
     * @param event The {@link EventFlags event}.
     * @return Whether the event occurred.
     */
    public boolean contains(@EventFlags int event) {
      return flags.contains(event);
    }

    /**
     * Returns whether any of the given events occurred.
     *
     * @param events The {@link EventFlags events}.
     * @return Whether any of the events occurred.
     */
    public boolean containsAny(@EventFlags int... events) {
      return flags.containsAny(events);
    }

    /** Returns the number of events in the set. */
    public int size() {
      return flags.size();
    }

    /**
     * Returns the {@link EventFlags event} at the given index.
     *
     * <p>Although index-based access is possible, it doesn't imply a particular order of these
     * events.
     *
     * @param index The index. Must be between 0 (inclusive) and {@link #size()} (exclusive).
     * @return The {@link EventFlags event} at the given index.
     */
    public @EventFlags int get(int index) {
      return flags.get(index);
    }
  }

  /**
   * Events that can be reported via {@link #onEvents(Player, Events)}.
   *
   * <p>One of the {@link AnalyticsListener}{@code .EVENT_*} flags.
   */
  // @Target list includes both 'default' targets and TYPE_USE, to ensure backwards compatibility
  // with Kotlin usages from before TYPE_USE was added.
  @UnstableApi
  @Documented
  @Retention(RetentionPolicy.SOURCE)
  @Target({FIELD, METHOD, PARAMETER, LOCAL_VARIABLE, TYPE_USE})
  @IntDef({
    EVENT_TIMELINE_CHANGED,
    EVENT_MEDIA_ITEM_TRANSITION,
    EVENT_TRACKS_CHANGED,
    EVENT_IS_LOADING_CHANGED,
    EVENT_PLAYBACK_STATE_CHANGED,
    EVENT_PLAY_WHEN_READY_CHANGED,
    EVENT_PLAYBACK_SUPPRESSION_REASON_CHANGED,
    EVENT_IS_PLAYING_CHANGED,
    EVENT_REPEAT_MODE_CHANGED,
    EVENT_SHUFFLE_MODE_ENABLED_CHANGED,
    EVENT_PLAYER_ERROR,
    EVENT_POSITION_DISCONTINUITY,
    EVENT_PLAYBACK_PARAMETERS_CHANGED,
    EVENT_AVAILABLE_COMMANDS_CHANGED,
    EVENT_MEDIA_METADATA_CHANGED,
    EVENT_PLAYLIST_METADATA_CHANGED,
    EVENT_SEEK_BACK_INCREMENT_CHANGED,
    EVENT_SEEK_FORWARD_INCREMENT_CHANGED,
    EVENT_MAX_SEEK_TO_PREVIOUS_POSITION_CHANGED,
    EVENT_TRACK_SELECTION_PARAMETERS_CHANGED,
    EVENT_DEVICE_INFO_CHANGED,
    EVENT_DEVICE_VOLUME_CHANGED,
    EVENT_LOAD_STARTED,
    EVENT_LOAD_COMPLETED,
    EVENT_LOAD_CANCELED,
    EVENT_LOAD_ERROR,
    EVENT_DOWNSTREAM_FORMAT_CHANGED,
    EVENT_UPSTREAM_DISCARDED,
    EVENT_BANDWIDTH_ESTIMATE,
    EVENT_METADATA,
    EVENT_CUES,
    EVENT_AUDIO_ENABLED,
    EVENT_AUDIO_DECODER_INITIALIZED,
    EVENT_AUDIO_INPUT_FORMAT_CHANGED,
    EVENT_AUDIO_POSITION_ADVANCING,
    EVENT_AUDIO_UNDERRUN,
    EVENT_AUDIO_DECODER_RELEASED,
    EVENT_AUDIO_DISABLED,
    EVENT_AUDIO_SESSION_ID,
    EVENT_AUDIO_ATTRIBUTES_CHANGED,
    EVENT_SKIP_SILENCE_ENABLED_CHANGED,
    EVENT_AUDIO_SINK_ERROR,
    EVENT_VOLUME_CHANGED,
    EVENT_VIDEO_ENABLED,
    EVENT_VIDEO_DECODER_INITIALIZED,
    EVENT_VIDEO_INPUT_FORMAT_CHANGED,
    EVENT_DROPPED_VIDEO_FRAMES,
    EVENT_VIDEO_DECODER_RELEASED,
    EVENT_VIDEO_DISABLED,
    EVENT_VIDEO_FRAME_PROCESSING_OFFSET,
    EVENT_RENDERED_FIRST_FRAME,
    EVENT_VIDEO_SIZE_CHANGED,
    EVENT_SURFACE_SIZE_CHANGED,
    EVENT_DRM_SESSION_ACQUIRED,
    EVENT_DRM_KEYS_LOADED,
    EVENT_DRM_SESSION_MANAGER_ERROR,
    EVENT_DRM_KEYS_RESTORED,
    EVENT_DRM_KEYS_REMOVED,
    EVENT_DRM_SESSION_RELEASED,
    EVENT_PLAYER_RELEASED,
    EVENT_AUDIO_CODEC_ERROR,
    EVENT_VIDEO_CODEC_ERROR,
    EVENT_AUDIO_TRACK_INITIALIZED,
    EVENT_AUDIO_TRACK_RELEASED,
    EVENT_RENDERER_READY_CHANGED
  })
  @interface EventFlags {}

  /** {@link Player#getCurrentTimeline()} changed. */
  @UnstableApi int EVENT_TIMELINE_CHANGED = Player.EVENT_TIMELINE_CHANGED;

  /**
   * {@link Player#getCurrentMediaItem()} changed or the player started repeating the current item.
   */
  @UnstableApi int EVENT_MEDIA_ITEM_TRANSITION = Player.EVENT_MEDIA_ITEM_TRANSITION;

  /** {@link Player#getCurrentTracks()} changed. */
  @UnstableApi int EVENT_TRACKS_CHANGED = Player.EVENT_TRACKS_CHANGED;

  /** {@link Player#isLoading()} ()} changed. */
  @UnstableApi int EVENT_IS_LOADING_CHANGED = Player.EVENT_IS_LOADING_CHANGED;

  /** {@link Player#getPlaybackState()} changed. */
  @UnstableApi int EVENT_PLAYBACK_STATE_CHANGED = Player.EVENT_PLAYBACK_STATE_CHANGED;

  /** {@link Player#getPlayWhenReady()} changed. */
  @UnstableApi int EVENT_PLAY_WHEN_READY_CHANGED = Player.EVENT_PLAY_WHEN_READY_CHANGED;

  /** {@link Player#getPlaybackSuppressionReason()} changed. */
  @UnstableApi
  int EVENT_PLAYBACK_SUPPRESSION_REASON_CHANGED = Player.EVENT_PLAYBACK_SUPPRESSION_REASON_CHANGED;

  /** {@link Player#isPlaying()} changed. */
  @UnstableApi int EVENT_IS_PLAYING_CHANGED = Player.EVENT_IS_PLAYING_CHANGED;

  /** {@link Player#getRepeatMode()} changed. */
  @UnstableApi int EVENT_REPEAT_MODE_CHANGED = Player.EVENT_REPEAT_MODE_CHANGED;

  /** {@link Player#getShuffleModeEnabled()} changed. */
  @UnstableApi int EVENT_SHUFFLE_MODE_ENABLED_CHANGED = Player.EVENT_SHUFFLE_MODE_ENABLED_CHANGED;

  /** {@link Player#getPlayerError()} changed. */
  @UnstableApi int EVENT_PLAYER_ERROR = Player.EVENT_PLAYER_ERROR;

  /**
   * A position discontinuity occurred. See {@link
   * Player.Listener#onPositionDiscontinuity(Player.PositionInfo, Player.PositionInfo, int)}.
   */
  @UnstableApi int EVENT_POSITION_DISCONTINUITY = Player.EVENT_POSITION_DISCONTINUITY;

  /** {@link Player#getPlaybackParameters()} changed. */
  @UnstableApi int EVENT_PLAYBACK_PARAMETERS_CHANGED = Player.EVENT_PLAYBACK_PARAMETERS_CHANGED;

  /** {@link Player#getAvailableCommands()} changed. */
  @UnstableApi int EVENT_AVAILABLE_COMMANDS_CHANGED = Player.EVENT_AVAILABLE_COMMANDS_CHANGED;

  /** {@link Player#getMediaMetadata()} changed. */
  @UnstableApi int EVENT_MEDIA_METADATA_CHANGED = Player.EVENT_MEDIA_METADATA_CHANGED;

  /** {@link Player#getPlaylistMetadata()} changed. */
  @UnstableApi int EVENT_PLAYLIST_METADATA_CHANGED = Player.EVENT_PLAYLIST_METADATA_CHANGED;

  /** {@link Player#getSeekBackIncrement()} changed. */
  @UnstableApi int EVENT_SEEK_BACK_INCREMENT_CHANGED = Player.EVENT_SEEK_BACK_INCREMENT_CHANGED;

  /** {@link Player#getSeekForwardIncrement()} changed. */
  @UnstableApi
  int EVENT_SEEK_FORWARD_INCREMENT_CHANGED = Player.EVENT_SEEK_FORWARD_INCREMENT_CHANGED;

  /** {@link Player#getMaxSeekToPreviousPosition()} changed. */
  @UnstableApi
  int EVENT_MAX_SEEK_TO_PREVIOUS_POSITION_CHANGED =
      Player.EVENT_MAX_SEEK_TO_PREVIOUS_POSITION_CHANGED;

  /** {@link Player#getTrackSelectionParameters()} changed. */
  @UnstableApi
  int EVENT_TRACK_SELECTION_PARAMETERS_CHANGED = Player.EVENT_TRACK_SELECTION_PARAMETERS_CHANGED;

  /** Audio attributes changed. */
  @UnstableApi int EVENT_AUDIO_ATTRIBUTES_CHANGED = Player.EVENT_AUDIO_ATTRIBUTES_CHANGED;

  /** An audio session id was set. */
  @UnstableApi int EVENT_AUDIO_SESSION_ID = Player.EVENT_AUDIO_SESSION_ID;

  /** The volume changed. */
  @UnstableApi int EVENT_VOLUME_CHANGED = Player.EVENT_VOLUME_CHANGED;

  /** Skipping silences was enabled or disabled in the audio stream. */
  @UnstableApi int EVENT_SKIP_SILENCE_ENABLED_CHANGED = Player.EVENT_SKIP_SILENCE_ENABLED_CHANGED;

  /** The surface size changed. */
  @UnstableApi int EVENT_SURFACE_SIZE_CHANGED = Player.EVENT_SURFACE_SIZE_CHANGED;

  /** The video size changed. */
  @UnstableApi int EVENT_VIDEO_SIZE_CHANGED = Player.EVENT_VIDEO_SIZE_CHANGED;

  /**
   * The first frame has been rendered since setting the surface, since the renderer was reset or
   * since the stream changed.
   */
  @UnstableApi int EVENT_RENDERED_FIRST_FRAME = Player.EVENT_RENDERED_FIRST_FRAME;

  /** Metadata associated with the current playback time was reported. */
  @UnstableApi int EVENT_METADATA = Player.EVENT_METADATA;

  /** {@link Player#getCurrentCues()} changed. */
  @UnstableApi int EVENT_CUES = Player.EVENT_CUES;

  /** {@link Player#getDeviceInfo()} changed. */
  @UnstableApi int EVENT_DEVICE_INFO_CHANGED = Player.EVENT_DEVICE_INFO_CHANGED;

  /** {@link Player#getDeviceVolume()} changed. */
  @UnstableApi int EVENT_DEVICE_VOLUME_CHANGED = Player.EVENT_DEVICE_VOLUME_CHANGED;

  /** A source started loading data. */
  @UnstableApi
  int EVENT_LOAD_STARTED = 1000; // Intentional gap to leave space for new Player events

  /** A source started completed loading data. */
  @UnstableApi int EVENT_LOAD_COMPLETED = 1001;

  /** A source canceled loading data. */
  @UnstableApi int EVENT_LOAD_CANCELED = 1002;

  /** A source had a non-fatal error loading data. */
  @UnstableApi int EVENT_LOAD_ERROR = 1003;

  /** The downstream format sent to renderers changed. */
  @UnstableApi int EVENT_DOWNSTREAM_FORMAT_CHANGED = 1004;

  /** Data was removed from the end of the media buffer. */
  @UnstableApi int EVENT_UPSTREAM_DISCARDED = 1005;

  /** The bandwidth estimate has been updated. */
  @UnstableApi int EVENT_BANDWIDTH_ESTIMATE = 1006;

  /** An audio renderer was enabled. */
  @UnstableApi int EVENT_AUDIO_ENABLED = 1007;

  /** An audio renderer created a decoder. */
  @UnstableApi int EVENT_AUDIO_DECODER_INITIALIZED = 1008;

  /** The format consumed by an audio renderer changed. */
  @UnstableApi int EVENT_AUDIO_INPUT_FORMAT_CHANGED = 1009;

  /** The audio position has increased for the first time since the last pause or position reset. */
  @UnstableApi int EVENT_AUDIO_POSITION_ADVANCING = 1010;

  /** An audio underrun occurred. */
  @UnstableApi int EVENT_AUDIO_UNDERRUN = 1011;

  /** An audio renderer released a decoder. */
  @UnstableApi int EVENT_AUDIO_DECODER_RELEASED = 1012;

  /** An audio renderer was disabled. */
  @UnstableApi int EVENT_AUDIO_DISABLED = 1013;

  /** The audio sink encountered a non-fatal error. */
  @UnstableApi int EVENT_AUDIO_SINK_ERROR = 1014;

  /** A video renderer was enabled. */
  @UnstableApi int EVENT_VIDEO_ENABLED = 1015;

  /** A video renderer created a decoder. */
  @UnstableApi int EVENT_VIDEO_DECODER_INITIALIZED = 1016;

  /** The format consumed by a video renderer changed. */
  @UnstableApi int EVENT_VIDEO_INPUT_FORMAT_CHANGED = 1017;

  /** Video frames have been dropped. */
  @UnstableApi int EVENT_DROPPED_VIDEO_FRAMES = 1018;

  /** A video renderer released a decoder. */
  @UnstableApi int EVENT_VIDEO_DECODER_RELEASED = 1019;

  /** A video renderer was disabled. */
  @UnstableApi int EVENT_VIDEO_DISABLED = 1020;

  /** Video frame processing offset data has been reported. */
  @UnstableApi int EVENT_VIDEO_FRAME_PROCESSING_OFFSET = 1021;

  /** A DRM session has been acquired. */
  @UnstableApi int EVENT_DRM_SESSION_ACQUIRED = 1022;

  /** DRM keys were loaded. */
  @UnstableApi int EVENT_DRM_KEYS_LOADED = 1023;

  /** A non-fatal DRM session manager error occurred. */
  @UnstableApi int EVENT_DRM_SESSION_MANAGER_ERROR = 1024;

  /** DRM keys were restored. */
  @UnstableApi int EVENT_DRM_KEYS_RESTORED = 1025;

  /** DRM keys were removed. */
  @UnstableApi int EVENT_DRM_KEYS_REMOVED = 1026;

  /** A DRM session has been released. */
  @UnstableApi int EVENT_DRM_SESSION_RELEASED = 1027;

  /** The player was released. */
  @UnstableApi int EVENT_PLAYER_RELEASED = 1028;

  /** The audio codec encountered an error. */
  @UnstableApi int EVENT_AUDIO_CODEC_ERROR = 1029;

  /** The video codec encountered an error. */
  @UnstableApi int EVENT_VIDEO_CODEC_ERROR = 1030;

  /** An audio track has been initialized. */
  @UnstableApi int EVENT_AUDIO_TRACK_INITIALIZED = 1031;

  /** An audio track has been released. */
  @UnstableApi int EVENT_AUDIO_TRACK_RELEASED = 1032;

  /** A renderer changed its readiness for playback. */
  @UnstableApi int EVENT_RENDERER_READY_CHANGED = 1033;

  /** Time information of an event. */
  @UnstableApi
  final class EventTime {

    /**
     * Elapsed real-time as returned by {@code SystemClock.elapsedRealtime()} at the time of the
     * event, in milliseconds.
     */
    public final long realtimeMs;

    /** Most recent {@link Timeline} that contains the event position. */
    public final Timeline timeline;

    /**
     * Window index in the {@link #timeline} this event belongs to, or the prospective window index
     * if the timeline is not yet known and empty.
     */
    public final int windowIndex;

    /**
     * {@link MediaPeriodId Media period identifier} for the media period this event belongs to, or
     * {@code null} if the event is not associated with a specific media period.
     */
    @Nullable public final MediaPeriodId mediaPeriodId;

    /**
     * Position in the window or ad this event belongs to at the time of the event, in milliseconds.
     */
    public final long eventPlaybackPositionMs;

    /**
     * The current {@link Timeline} at the time of the event (equivalent to {@link
     * Player#getCurrentTimeline()}).
     */
    public final Timeline currentTimeline;

    /**
     * The current window index in {@link #currentTimeline} at the time of the event, or the
     * prospective window index if the timeline is not yet known and empty (equivalent to {@link
     * Player#getCurrentMediaItemIndex()}).
     */
    public final int currentWindowIndex;

    /**
     * {@link MediaPeriodId Media period identifier} for the currently playing media period at the
     * time of the event, or {@code null} if no current media period identifier is available.
     */
    @Nullable public final MediaPeriodId currentMediaPeriodId;

    /**
     * Position in the {@link #currentWindowIndex current timeline window} or the currently playing
     * ad at the time of the event, in milliseconds.
     */
    public final long currentPlaybackPositionMs;

    /**
     * Total buffered duration from {@link #currentPlaybackPositionMs} at the time of the event, in
     * milliseconds. This includes pre-buffered data for subsequent ads and windows.
     */
    public final long totalBufferedDurationMs;

    /**
     * @param realtimeMs Elapsed real-time as returned by {@code SystemClock.elapsedRealtime()} at
     *     the time of the event, in milliseconds.
     * @param timeline Most recent {@link Timeline} that contains the event position.
     * @param windowIndex Window index in the {@code timeline} this event belongs to, or the
     *     prospective window index if the timeline is not yet known and empty.
     * @param mediaPeriodId {@link MediaPeriodId Media period identifier} for the media period this
     *     event belongs to, or {@code null} if the event is not associated with a specific media
     *     period.
     * @param eventPlaybackPositionMs Position in the window or ad this event belongs to at the time
     *     of the event, in milliseconds.
     * @param currentTimeline The current {@link Timeline} at the time of the event (equivalent to
     *     {@link Player#getCurrentTimeline()}).
     * @param currentWindowIndex The current window index in {@code currentTimeline} at the time of
     *     the event, or the prospective window index if the timeline is not yet known and empty
     *     (equivalent to {@link Player#getCurrentMediaItemIndex()}).
     * @param currentMediaPeriodId {@link MediaPeriodId Media period identifier} for the currently
     *     playing media period at the time of the event, or {@code null} if no current media period
     *     identifier is available.
     * @param currentPlaybackPositionMs Position in the current timeline window or the currently
     *     playing ad at the time of the event, in milliseconds.
     * @param totalBufferedDurationMs Total buffered duration from {@code currentPlaybackPositionMs}
     *     at the time of the event, in milliseconds. This includes pre-buffered data for subsequent
     *     ads and windows.
     */
    public EventTime(
        long realtimeMs,
        Timeline timeline,
        int windowIndex,
        @Nullable MediaPeriodId mediaPeriodId,
        long eventPlaybackPositionMs,
        Timeline currentTimeline,
        int currentWindowIndex,
        @Nullable MediaPeriodId currentMediaPeriodId,
        long currentPlaybackPositionMs,
        long totalBufferedDurationMs) {
      this.realtimeMs = realtimeMs;
      this.timeline = timeline;
      this.windowIndex = windowIndex;
      this.mediaPeriodId = mediaPeriodId;
      this.eventPlaybackPositionMs = eventPlaybackPositionMs;
      this.currentTimeline = currentTimeline;
      this.currentWindowIndex = currentWindowIndex;
      this.currentMediaPeriodId = currentMediaPeriodId;
      this.currentPlaybackPositionMs = currentPlaybackPositionMs;
      this.totalBufferedDurationMs = totalBufferedDurationMs;
    }

    @Override
    public boolean equals(@Nullable Object o) {
      if (this == o) {
        return true;
      }
      if (o == null || getClass() != o.getClass()) {
        return false;
      }
      EventTime eventTime = (EventTime) o;
      return realtimeMs == eventTime.realtimeMs
          && windowIndex == eventTime.windowIndex
          && eventPlaybackPositionMs == eventTime.eventPlaybackPositionMs
          && currentWindowIndex == eventTime.currentWindowIndex
          && currentPlaybackPositionMs == eventTime.currentPlaybackPositionMs
          && totalBufferedDurationMs == eventTime.totalBufferedDurationMs
          && Objects.equal(timeline, eventTime.timeline)
          && Objects.equal(mediaPeriodId, eventTime.mediaPeriodId)
          && Objects.equal(currentTimeline, eventTime.currentTimeline)
          && Objects.equal(currentMediaPeriodId, eventTime.currentMediaPeriodId);
    }

    @Override
    public int hashCode() {
      return Objects.hashCode(
          realtimeMs,
          timeline,
          windowIndex,
          mediaPeriodId,
          eventPlaybackPositionMs,
          currentTimeline,
          currentWindowIndex,
          currentMediaPeriodId,
          currentPlaybackPositionMs,
          totalBufferedDurationMs);
    }
  }

  /**
   * @deprecated Use {@link #onPlaybackStateChanged(EventTime, int)} and {@link
   *     #onPlayWhenReadyChanged(EventTime, boolean, int)} instead.
   */
  @UnstableApi
  @Deprecated
  default void onPlayerStateChanged(
      EventTime eventTime, boolean playWhenReady, @Player.State int playbackState) {}

  /**
   * Called when the playback state changed.
   *
   * @param eventTime The event time.
   * @param state The new {@link Player.State playback state}.
   */
  @UnstableApi
  default void onPlaybackStateChanged(EventTime eventTime, @Player.State int state) {}

  /**
   * Called when the value changed that indicates whether playback will proceed when ready.
   *
   * @param eventTime The event time.
   * @param playWhenReady Whether playback will proceed when ready.
   * @param reason The {@link Player.PlayWhenReadyChangeReason reason} of the change.
   */
  @UnstableApi
  default void onPlayWhenReadyChanged(
      EventTime eventTime, boolean playWhenReady, @Player.PlayWhenReadyChangeReason int reason) {}

  /**
   * Called when playback suppression reason changed.
   *
   * @param eventTime The event time.
   * @param playbackSuppressionReason The new {@link PlaybackSuppressionReason}.
   */
  @UnstableApi
  default void onPlaybackSuppressionReasonChanged(
      EventTime eventTime, @PlaybackSuppressionReason int playbackSuppressionReason) {}

  /**
   * Called when the player starts or stops playing.
   *
   * @param eventTime The event time.
   * @param isPlaying Whether the player is playing.
   */
  @UnstableApi
  default void onIsPlayingChanged(EventTime eventTime, boolean isPlaying) {}

  /**
   * Called when the timeline changed.
   *
   * @param eventTime The event time.
   * @param reason The reason for the timeline change.
   */
  @UnstableApi
  default void onTimelineChanged(EventTime eventTime, @TimelineChangeReason int reason) {}

  /**
   * Called when playback transitions to a different media item.
   *
   * @param eventTime The event time.
   * @param mediaItem The media item.
   * @param reason The reason for the media item transition.
   */
  @UnstableApi
  default void onMediaItemTransition(
      EventTime eventTime,
      @Nullable MediaItem mediaItem,
      @Player.MediaItemTransitionReason int reason) {}

  /**
   * @deprecated Use {@link #onPositionDiscontinuity(EventTime, Player.PositionInfo,
   *     Player.PositionInfo, int)} instead.
   */
  @UnstableApi
  @Deprecated
  default void onPositionDiscontinuity(EventTime eventTime, @DiscontinuityReason int reason) {}

  /**
   * Called when a position discontinuity occurred.
   *
   * @param eventTime The event time.
   * @param oldPosition The position before the discontinuity.
   * @param newPosition The position after the discontinuity.
   * @param reason The reason for the position discontinuity.
   */
  @UnstableApi
  default void onPositionDiscontinuity(
      EventTime eventTime,
      Player.PositionInfo oldPosition,
      Player.PositionInfo newPosition,
      @DiscontinuityReason int reason) {}

  /**
   * @deprecated Use {@link #onPositionDiscontinuity(EventTime, Player.PositionInfo,
   *     Player.PositionInfo, int)} instead, listening to changes with {@link
   *     Player#DISCONTINUITY_REASON_SEEK}.
   */
  @UnstableApi
  @Deprecated
  default void onSeekStarted(EventTime eventTime) {}

  /**
   * Called when the playback parameters changed.
   *
   * @param eventTime The event time.
   * @param playbackParameters The new playback parameters.
   */
  @UnstableApi
  default void onPlaybackParametersChanged(
      EventTime eventTime, PlaybackParameters playbackParameters) {}

  /**
   * Called when the seek back increment changed.
   *
   * @param eventTime The event time.
   * @param seekBackIncrementMs The seek back increment, in milliseconds.
   */
  @UnstableApi
  default void onSeekBackIncrementChanged(EventTime eventTime, long seekBackIncrementMs) {}

  /**
   * Called when the seek forward increment changed.
   *
   * @param eventTime The event time.
   * @param seekForwardIncrementMs The seek forward increment, in milliseconds.
   */
  @UnstableApi
  default void onSeekForwardIncrementChanged(EventTime eventTime, long seekForwardIncrementMs) {}

  /**
   * Called when the maximum position for which {@link Player#seekToPrevious()} seeks to the
   * previous window changes.
   *
   * @param eventTime The event time.
   * @param maxSeekToPreviousPositionMs The maximum seek to previous position, in milliseconds.
   */
  @UnstableApi
  default void onMaxSeekToPreviousPositionChanged(
      EventTime eventTime, long maxSeekToPreviousPositionMs) {}

  /**
   * Called when the repeat mode changed.
   *
   * @param eventTime The event time.
   * @param repeatMode The new repeat mode.
   */
  @UnstableApi
  default void onRepeatModeChanged(EventTime eventTime, @Player.RepeatMode int repeatMode) {}

  /**
   * Called when the shuffle mode changed.
   *
   * @param eventTime The event time.
   * @param shuffleModeEnabled Whether the shuffle mode is enabled.
   */
  @UnstableApi
  default void onShuffleModeChanged(EventTime eventTime, boolean shuffleModeEnabled) {}

  /**
   * Called when the player starts or stops loading data from a source.
   *
   * @param eventTime The event time.
   * @param isLoading Whether the player is loading.
   */
  @UnstableApi
  default void onIsLoadingChanged(EventTime eventTime, boolean isLoading) {}

  /**
   * @deprecated Use {@link #onIsLoadingChanged(EventTime, boolean)} instead.
   */
  @UnstableApi
  @Deprecated
  default void onLoadingChanged(EventTime eventTime, boolean isLoading) {}

  /**
   * Called when the player's available commands changed.
   *
   * @param eventTime The event time.
   * @param availableCommands The available commands.
   */
  @UnstableApi
  default void onAvailableCommandsChanged(EventTime eventTime, Player.Commands availableCommands) {}

  /**
   * Called when a fatal player error occurred.
   *
   * <p>Implementations of {@link Player} may pass an instance of a subclass of {@link
   * PlaybackException} to this method in order to include more information about the error.
   *
   * @param eventTime The event time.
   * @param error The error.
   */
  @UnstableApi
  default void onPlayerError(EventTime eventTime, PlaybackException error) {}

  /**
   * Called when the {@link PlaybackException} returned by {@link Player#getPlayerError()} changes.
   *
   * <p>Implementations of Player may pass an instance of a subclass of {@link PlaybackException} to
   * this method in order to include more information about the error.
   *
   * @param eventTime The event time.
   * @param error The new error, or null if the error is being cleared.
   */
  @UnstableApi
  default void onPlayerErrorChanged(EventTime eventTime, @Nullable PlaybackException error) {}

  /**
   * Called when the tracks change.
   *
   * @param eventTime The event time.
   * @param tracks The tracks. Never null, but may be of length zero.
   */
  @UnstableApi
  default void onTracksChanged(EventTime eventTime, Tracks tracks) {}

  /**
   * Called when track selection parameters change.
   *
   * @param eventTime The event time.
   * @param trackSelectionParameters The new {@link TrackSelectionParameters}.
   */
  @UnstableApi
  default void onTrackSelectionParametersChanged(
      EventTime eventTime, TrackSelectionParameters trackSelectionParameters) {}

  /**
   * Called when the combined {@link MediaMetadata} changes.
   *
   * <p>The provided {@link MediaMetadata} is a combination of the {@link MediaItem#mediaMetadata}
   * and the static and dynamic metadata from the {@link TrackSelection#getFormat(int) track
   * selections' formats} and {@link MetadataOutput#onMetadata(Metadata)}.
   *
   * @param eventTime The event time.
   * @param mediaMetadata The combined {@link MediaMetadata}.
   */
  @UnstableApi
  default void onMediaMetadataChanged(EventTime eventTime, MediaMetadata mediaMetadata) {}

  /**
   * Called when the playlist {@link MediaMetadata} changes.
   *
   * @param eventTime The event time.
   * @param playlistMetadata The playlist {@link MediaMetadata}.
   */
  @UnstableApi
  default void onPlaylistMetadataChanged(EventTime eventTime, MediaMetadata playlistMetadata) {}

  /**
   * Called when a media source started loading data.
   *
   * @param eventTime The event time.
   * @param loadEventInfo The {@link LoadEventInfo} defining the load event.
   * @param mediaLoadData The {@link MediaLoadData} defining the data being loaded.
   */
  @UnstableApi
  default void onLoadStarted(
      EventTime eventTime, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData) {}

  /**
   * Called when a media source completed loading data.
   *
   * @param eventTime The event time.
   * @param loadEventInfo The {@link LoadEventInfo} defining the load event.
   * @param mediaLoadData The {@link MediaLoadData} defining the data being loaded.
   */
  @UnstableApi
  default void onLoadCompleted(
      EventTime eventTime, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData) {}

  /**
   * Called when a media source canceled loading data.
   *
   * @param eventTime The event time.
   * @param loadEventInfo The {@link LoadEventInfo} defining the load event.
   * @param mediaLoadData The {@link MediaLoadData} defining the data being loaded.
   */
  @UnstableApi
  default void onLoadCanceled(
      EventTime eventTime, LoadEventInfo loadEventInfo, MediaLoadData mediaLoadData) {}

  /**
   * Called when a media source loading error occurred.
   *
   * <p>This method being called does not indicate that playback has failed, or that it will fail.
   * The player may be able to recover from the error. Hence applications should <em>not</em>
   * implement this method to display a user visible error or initiate an application level retry.
   * {@link Player.Listener#onPlayerError} is the appropriate place to implement such behavior. This
   * method is called to provide the application with an opportunity to log the error if it wishes
   * to do so.
   *
   * @param eventTime The event time.
   * @param loadEventInfo The {@link LoadEventInfo} defining the load event.
   * @param mediaLoadData The {@link MediaLoadData} defining the data being loaded.
   * @param error The load error.
   * @param wasCanceled Whether the load was canceled as a result of the error.
   */
  @UnstableApi
  default void onLoadError(
      EventTime eventTime,
      LoadEventInfo loadEventInfo,
      MediaLoadData mediaLoadData,
      IOException error,
      boolean wasCanceled) {}

  /**
   * Called when the downstream format sent to the renderers changed.
   *
   * @param eventTime The event time.
   * @param mediaLoadData The {@link MediaLoadData} defining the newly selected media data.
   */
  @UnstableApi
  default void onDownstreamFormatChanged(EventTime eventTime, MediaLoadData mediaLoadData) {}

  /**
   * Called when data is removed from the back of a media buffer, typically so that it can be
   * re-buffered in a different format.
   *
   * @param eventTime The event time.
   * @param mediaLoadData The {@link MediaLoadData} defining the media being discarded.
   */
  @UnstableApi
  default void onUpstreamDiscarded(EventTime eventTime, MediaLoadData mediaLoadData) {}

  /**
   * Called when the bandwidth estimate for the current data source has been updated.
   *
   * @param eventTime The event time.
   * @param totalLoadTimeMs The total time spend loading this update is based on, in milliseconds.
   * @param totalBytesLoaded The total bytes loaded this update is based on.
   * @param bitrateEstimate The bandwidth estimate, in bits per second.
   */
  @UnstableApi
  default void onBandwidthEstimate(
      EventTime eventTime, int totalLoadTimeMs, long totalBytesLoaded, long bitrateEstimate) {}

  /**
   * Called when there is {@link Metadata} associated with the current playback time.
   *
   * @param eventTime The event time.
   * @param metadata The metadata.
   */
  @UnstableApi
  default void onMetadata(EventTime eventTime, Metadata metadata) {}

  /**
   * Called when there is a change in the {@link Cue Cues}.
   *
   * <p>Both {@link #onCues(EventTime, List)} and {@link #onCues(EventTime, CueGroup)} are called
   * when there is a change in the cues. You should only implement one or the other.
   *
   * @param eventTime The event time.
   * @param cues The {@link Cue Cues}.
   * @deprecated Use {@link #onCues(EventTime, CueGroup)} instead.
   */
  @Deprecated
  @UnstableApi
  default void onCues(EventTime eventTime, List<Cue> cues) {}

  /**
   * Called when there is a change in the {@link CueGroup}.
   *
   * <p>Both {@link #onCues(EventTime, List)} and {@link #onCues(EventTime, CueGroup)} are called
   * when there is a change in the cues. You should only implement one or the other.
   *
   * @param eventTime The event time.
   * @param cueGroup The {@link CueGroup}.
   */
  @UnstableApi
  default void onCues(EventTime eventTime, CueGroup cueGroup) {}

  /**
   * Called when an audio renderer is enabled.
   *
   * @param eventTime The event time.
   * @param decoderCounters {@link DecoderCounters} that will be updated by the renderer for as long
   *     as it remains enabled.
   */
  @UnstableApi
  default void onAudioEnabled(EventTime eventTime, DecoderCounters decoderCounters) {}

  /**
   * Called when an audio renderer creates a decoder.
   *
   * @param eventTime The event time.
   * @param decoderName The decoder that was created.
   * @param initializedTimestampMs {@link SystemClock#elapsedRealtime()} when initialization
   *     finished.
   * @param initializationDurationMs The time taken to initialize the decoder in milliseconds.
   */
  @UnstableApi
  default void onAudioDecoderInitialized(
      EventTime eventTime,
      String decoderName,
      long initializedTimestampMs,
      long initializationDurationMs) {}

  /**
   * @deprecated Use {@link #onAudioDecoderInitialized(EventTime, String, long, long)}.
   */
  @UnstableApi
  @Deprecated
  default void onAudioDecoderInitialized(
      EventTime eventTime, String decoderName, long initializationDurationMs) {}

  /**
   * Called when the format of the media being consumed by an audio renderer changes.
   *
   * @param eventTime The event time.
   * @param format The new format.
   * @param decoderReuseEvaluation The result of the evaluation to determine whether an existing
   *     decoder instance can be reused for the new format, or {@code null} if the renderer did not
   *     have a decoder.
   */
  @UnstableApi
  default void onAudioInputFormatChanged(
      EventTime eventTime,
      Format format,
      @Nullable DecoderReuseEvaluation decoderReuseEvaluation) {}

  /**
   * Called when the audio position has increased for the first time since the last pause or
   * position reset.
   *
   * @param eventTime The event time.
   * @param playoutStartSystemTimeMs The approximate derived {@link System#currentTimeMillis()} at
   *     which playout started.
   */
  @UnstableApi
  default void onAudioPositionAdvancing(EventTime eventTime, long playoutStartSystemTimeMs) {}

  /**
   * Called when an audio underrun occurs.
   *
   * @param eventTime The event time.
   * @param bufferSize The size of the audio output buffer, in bytes.
   * @param bufferSizeMs The size of the audio output buffer, in milliseconds, if it contains PCM
   *     encoded audio. {@link C#TIME_UNSET} if the output buffer contains non-PCM encoded audio.
   * @param elapsedSinceLastFeedMs The time since audio was last written to the output buffer.
   */
  @UnstableApi
  default void onAudioUnderrun(
      EventTime eventTime, int bufferSize, long bufferSizeMs, long elapsedSinceLastFeedMs) {}

  /**
   * Called when an audio renderer releases a decoder.
   *
   * @param eventTime The event time.
   * @param decoderName The decoder that was released.
   */
  @UnstableApi
  default void onAudioDecoderReleased(EventTime eventTime, String decoderName) {}

  /**
   * Called when an audio renderer is disabled.
   *
   * @param eventTime The event time.
   * @param decoderCounters {@link DecoderCounters} that were updated by the renderer.
   */
  @UnstableApi
  default void onAudioDisabled(EventTime eventTime, DecoderCounters decoderCounters) {}

  /**
   * Called when the audio session ID changes.
   *
   * @param eventTime The event time.
   * @param audioSessionId The audio session ID.
   */
  @UnstableApi
  default void onAudioSessionIdChanged(EventTime eventTime, int audioSessionId) {}

  /**
   * Called when the audio attributes change.
   *
   * @param eventTime The event time.
   * @param audioAttributes The audio attributes.
   */
  @UnstableApi
  default void onAudioAttributesChanged(EventTime eventTime, AudioAttributes audioAttributes) {}

  /**
   * Called when skipping silences is enabled or disabled in the audio stream.
   *
   * @param eventTime The event time.
   * @param skipSilenceEnabled Whether skipping silences in the audio stream is enabled.
   */
  @UnstableApi
  default void onSkipSilenceEnabledChanged(EventTime eventTime, boolean skipSilenceEnabled) {}

  /**
   * Called when {@link AudioSink} has encountered an error.
   *
   * <p>This method being called does not indicate that playback has failed, or that it will fail.
   * The player may be able to recover from the error. Hence applications should <em>not</em>
   * implement this method to display a user visible error or initiate an application level retry.
   * {@link Player.Listener#onPlayerError} is the appropriate place to implement such behavior. This
   * method is called to provide the application with an opportunity to log the error if it wishes
   * to do so.
   *
   * @param eventTime The event time.
   * @param audioSinkError The error that occurred. Typically an {@link
   *     AudioSink.InitializationException}, a {@link AudioSink.WriteException}, or an {@link
   *     AudioSink.UnexpectedDiscontinuityException}.
   */
  @UnstableApi
  default void onAudioSinkError(EventTime eventTime, Exception audioSinkError) {}

  /**
   * Called when an audio decoder encounters an error.
   *
   * <p>This method being called does not indicate that playback has failed, or that it will fail.
   * The player may be able to recover from the error. Hence applications should <em>not</em>
   * implement this method to display a user visible error or initiate an application level retry.
   * {@link Player.Listener#onPlayerError} is the appropriate place to implement such behavior. This
   * method is called to provide the application with an opportunity to log the error if it wishes
   * to do so.
   *
   * @param eventTime The event time.
   * @param audioCodecError The error. Typically a {@link CodecException} if the renderer uses
   *     {@link MediaCodec}, or a {@link DecoderException} if the renderer uses a software decoder.
   */
  @UnstableApi
  default void onAudioCodecError(EventTime eventTime, Exception audioCodecError) {}

  /**
   * Called when an {@link AudioTrack} has been initialized.
   *
   * @param eventTime The event time.
   * @param audioTrackConfig The {@link AudioSink.AudioTrackConfig} of the initialized {@link
   *     AudioTrack}.
   */
  @UnstableApi
  default void onAudioTrackInitialized(
      EventTime eventTime, AudioSink.AudioTrackConfig audioTrackConfig) {}

  /**
   * Called when an {@link AudioTrack} has been released.
   *
   * @param eventTime The event time.
   * @param audioTrackConfig The {@link AudioSink.AudioTrackConfig} of the released {@link
   *     AudioTrack}.
   */
  @UnstableApi
  default void onAudioTrackReleased(
      EventTime eventTime, AudioSink.AudioTrackConfig audioTrackConfig) {}

  /**
   * Called when the volume changes.
   *
   * @param eventTime The event time.
   * @param volume The new volume, with 0 being silence and 1 being unity gain.
   */
  @UnstableApi
  default void onVolumeChanged(EventTime eventTime, float volume) {}

  /**
   * Called when the device information changes
   *
   * @param eventTime The event time.
   * @param deviceInfo The new {@link DeviceInfo}.
   */
  @UnstableApi
  default void onDeviceInfoChanged(EventTime eventTime, DeviceInfo deviceInfo) {}

  /**
   * Called when the device volume or mute state changes.
   *
   * @param eventTime The event time.
   * @param volume The new device volume, with 0 being silence and 1 being unity gain.
   * @param muted Whether the device is muted.
   */
  @UnstableApi
  default void onDeviceVolumeChanged(EventTime eventTime, int volume, boolean muted) {}

  /**
   * Called when a video renderer is enabled.
   *
   * @param eventTime The event time.
   * @param decoderCounters {@link DecoderCounters} that will be updated by the renderer for as long
   *     as it remains enabled.
   */
  @UnstableApi
  default void onVideoEnabled(EventTime eventTime, DecoderCounters decoderCounters) {}

  /**
   * Called when a video renderer creates a decoder.
   *
   * @param eventTime The event time.
   * @param decoderName The decoder that was created.
   * @param initializedTimestampMs {@link SystemClock#elapsedRealtime()} when initialization
   *     finished.
   * @param initializationDurationMs The time taken to initialize the decoder in milliseconds.
   */
  @UnstableApi
  default void onVideoDecoderInitialized(
      EventTime eventTime,
      String decoderName,
      long initializedTimestampMs,
      long initializationDurationMs) {}

  /**
   * @deprecated Use {@link #onVideoDecoderInitialized(EventTime, String, long, long)}.
   */
  @UnstableApi
  @Deprecated
  default void onVideoDecoderInitialized(
      EventTime eventTime, String decoderName, long initializationDurationMs) {}

  /**
   * Called when the format of the media being consumed by a video renderer changes.
   *
   * @param eventTime The event time.
   * @param format The new format.
   * @param decoderReuseEvaluation The result of the evaluation to determine whether an existing
   *     decoder instance can be reused for the new format, or {@code null} if the renderer did not
   *     have a decoder.
   */
  @UnstableApi
  default void onVideoInputFormatChanged(
      EventTime eventTime,
      Format format,
      @Nullable DecoderReuseEvaluation decoderReuseEvaluation) {}

  /**
   * Called after video frames have been dropped.
   *
   * @param eventTime The event time.
   * @param droppedFrames The number of dropped frames since the last call to this method.
   * @param elapsedMs The duration in milliseconds over which the frames were dropped. This duration
   *     is timed from when the renderer was started or from when dropped frames were last reported
   *     (whichever was more recent), and not from when the first of the reported drops occurred.
   */
  @UnstableApi
  default void onDroppedVideoFrames(EventTime eventTime, int droppedFrames, long elapsedMs) {}

  /**
   * Called when a video renderer releases a decoder.
   *
   * @param eventTime The event time.
   * @param decoderName The decoder that was released.
   */
  @UnstableApi
  default void onVideoDecoderReleased(EventTime eventTime, String decoderName) {}

  /**
   * Called when a video renderer is disabled.
   *
   * @param eventTime The event time.
   * @param decoderCounters {@link DecoderCounters} that were updated by the renderer.
   */
  @UnstableApi
  default void onVideoDisabled(EventTime eventTime, DecoderCounters decoderCounters) {}

  /**
   * Called when there is an update to the video frame processing offset reported by a video
   * renderer.
   *
   * <p>The processing offset for a video frame is the difference between the time at which the
   * frame became available to render, and the time at which it was scheduled to be rendered. A
   * positive value indicates the frame became available early enough, whereas a negative value
   * indicates that the frame wasn't available until after the time at which it should have been
   * rendered.
   *
   * @param eventTime The event time.
   * @param totalProcessingOffsetUs The sum of the video frame processing offsets for frames
   *     rendered since the last call to this method.
   * @param frameCount The number to samples included in {@code totalProcessingOffsetUs}.
   */
  @UnstableApi
  default void onVideoFrameProcessingOffset(
      EventTime eventTime, long totalProcessingOffsetUs, int frameCount) {}

  /**
   * Called when a video decoder encounters an error.
   *
   * <p>This method being called does not indicate that playback has failed, or that it will fail.
   * The player may be able to recover from the error. Hence applications should <em>not</em>
   * implement this method to display a user visible error or initiate an application level retry.
   * {@link Player.Listener#onPlayerError} is the appropriate place to implement such behavior. This
   * method is called to provide the application with an opportunity to log the error if it wishes
   * to do so.
   *
   * @param eventTime The event time.
   * @param videoCodecError The error. Typically a {@link CodecException} if the renderer uses
   *     {@link MediaCodec}, or a {@link DecoderException} if the renderer uses a software decoder.
   */
  @UnstableApi
  default void onVideoCodecError(EventTime eventTime, Exception videoCodecError) {}

  /**
   * Called when a frame is rendered for the first time since setting the surface, or since the
   * renderer was reset, or since the stream being rendered was changed.
   *
   * @param eventTime The event time.
   * @param output The output to which a frame has been rendered. Normally a {@link Surface},
   *     however may also be other output types (e.g., a {@link VideoDecoderOutputBufferRenderer}).
   * @param renderTimeMs {@link SystemClock#elapsedRealtime()} when the first frame was rendered.
   */
  @UnstableApi
  default void onRenderedFirstFrame(EventTime eventTime, Object output, long renderTimeMs) {}

  /**
   * Called before a frame is rendered for the first time since setting the surface, and each time
   * there's a change in the size or pixel aspect ratio of the video being rendered.
   *
   * @param eventTime The event time.
   * @param videoSize The new size of the video.
   */
  @UnstableApi
  default void onVideoSizeChanged(EventTime eventTime, VideoSize videoSize) {}

  /**
   * @deprecated Implement {@link #onVideoSizeChanged(EventTime eventTime, VideoSize)} instead.
   */
  @UnstableApi
  @Deprecated
  default void onVideoSizeChanged(
      EventTime eventTime,
      int width,
      int height,
      int unappliedRotationDegrees,
      float pixelWidthHeightRatio) {}

  /**
   * Called when the output surface size changed.
   *
   * @param eventTime The event time.
   * @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.
   */
  @UnstableApi
  default void onSurfaceSizeChanged(EventTime eventTime, int width, int height) {}

  /**
   * @deprecated Implement {@link #onDrmSessionAcquired(EventTime, int)} instead.
   */
  @UnstableApi
  @Deprecated
  default void onDrmSessionAcquired(EventTime eventTime) {}

  /**
   * Called each time a drm session is acquired.
   *
   * @param eventTime The event time.
   * @param state The {@link DrmSession.State} of the session when the acquisition completed.
   */
  @UnstableApi
  default void onDrmSessionAcquired(EventTime eventTime, @DrmSession.State int state) {}

  /**
   * Called each time drm keys are loaded.
   *
   * @param eventTime The event time.
   */
  @UnstableApi
  default void onDrmKeysLoaded(EventTime eventTime) {}

  /**
   * Called when a drm error occurs.
   *
   * <p>This method being called does not indicate that playback has failed, or that it will fail.
   * The player may be able to recover from the error. Hence applications should <em>not</em>
   * implement this method to display a user visible error or initiate an application level retry.
   * {@link Player.Listener#onPlayerError} is the appropriate place to implement such behavior. This
   * method is called to provide the application with an opportunity to log the error if it wishes
   * to do so.
   *
   * @param eventTime The event time.
   * @param error The error.
   */
  @UnstableApi
  default void onDrmSessionManagerError(EventTime eventTime, Exception error) {}

  /**
   * Called each time offline drm keys are restored.
   *
   * @param eventTime The event time.
   */
  @UnstableApi
  default void onDrmKeysRestored(EventTime eventTime) {}

  /**
   * Called each time offline drm keys are removed.
   *
   * @param eventTime The event time.
   */
  @UnstableApi
  default void onDrmKeysRemoved(EventTime eventTime) {}

  /**
   * Called each time a drm session is released.
   *
   * @param eventTime The event time.
   */
  @UnstableApi
  default void onDrmSessionReleased(EventTime eventTime) {}

  /**
   * Called each time a renderer starts or stops allowing playback to be ready.
   *
   * @param eventTime The event time.
   * @param rendererIndex The index of the renderer in the {@link
   *     androidx.media3.exoplayer.ExoPlayer} instance.
   * @param rendererTrackType The {@link C.TrackType} of the renderer.
   * @param isRendererReady Whether the renderer allows playback to be ready.
   */
  @UnstableApi
  default void onRendererReadyChanged(
      EventTime eventTime,
      int rendererIndex,
      @C.TrackType int rendererTrackType,
      boolean isRendererReady) {}

  /**
   * Called when the {@link Player} is released.
   *
   * @param eventTime The event time.
   */
  @UnstableApi
  default void onPlayerReleased(EventTime eventTime) {}

  /**
   * Called after one or more events occurred.
   *
   * <p>State changes and events that happen within one {@link Looper} message queue iteration are
   * reported together and only after all individual callbacks were triggered.
   *
   * <p>Listeners should prefer this method over individual callbacks in the following cases:
   *
   * <ul>
   *   <li>They intend to trigger the same logic for multiple events (e.g. when updating a UI for
   *       both {@link #onPlaybackStateChanged(EventTime, int)} and {@link
   *       #onPlayWhenReadyChanged(EventTime, boolean, int)}).
   *   <li>They need access to the {@link Player} object to trigger further events (e.g. to call
   *       {@link Player#seekTo(long)} after a {@link
   *       AnalyticsListener#onMediaItemTransition(EventTime, MediaItem, int)}).
   *   <li>They intend to use multiple state values together or in combination with {@link Player}
   *       getter methods. For example using {@link Player#getCurrentMediaItemIndex()} with the
   *       {@code timeline} provided in {@link #onTimelineChanged(EventTime, int)} is only safe from
   *       within this method.
   *   <li>They are interested in events that logically happened together (e.g {@link
   *       #onPlaybackStateChanged(EventTime, int)} to {@link Player#STATE_BUFFERING} because of
   *       {@link #onMediaItemTransition(EventTime, MediaItem, int)}).
   * </ul>
   *
   * @param player The {@link Player}.
   * @param events The {@link Events} that occurred in this iteration.
   */
  @UnstableApi
  default void onEvents(Player player, Events events) {}
}